
WiFi provisioning—the process of configuring an IoT device to connect to a user’s home network—is one of the most critical yet challenging aspects of IoT product development. What appears simple (connect device to WiFi) involves navigating a maze of platform restrictions, security requirements, network edge cases, and user experience challenges.
This article explores the complete landscape of WiFi provisioning, covering technical approaches, platform-specific limitations, and real-world solutions.
The Provisioning Challenge
The Core Problem
IoT devices need WiFi credentials to connect to a network, but they have no keyboard, display, or browser to enter credentials through traditional means. The provisioning solution must bridge this gap while maintaining security and providing excellent user experience.
Key Requirements
A robust provisioning solution must handle:
- Credential Transfer: Securely transmit SSID and password from user’s phone to device
- Network Discovery: Help users identify and select their target network
- Error Recovery: Handle failures gracefully (wrong password, signal issues, network changes)
- Security: Protect credentials during transmission and storage
- Cross-Platform: Work consistently on both iOS and Android
- Edge Cases: Captive portals, hidden SSIDs, special characters, enterprise networks
Common Provisioning Architectures
1. SoftAP (Access Point) Mode
How it works:
- Device creates its own temporary WiFi network
- User connects phone to device’s network
- App communicates with device via HTTP/socket
- App sends home WiFi credentials
- Device switches to home network
- Phone reconnects to home network
Advantages:
- Simple, widely compatible
- Works on all platforms
- No special hardware required
- Can use HTTP or raw socket communication
Disadvantages:
- Poor UX (user manually switches networks twice)
- OS warnings about “no internet” connection
- Can drop unexpectedly on modern mobile OS
- Android 10+ requires user dialog approval
Technical Implementation:
Device creates AP:
SSID: "DeviceName-Setup-XXXX" IP: 192.168.4.1 (common default) Security: WPA2 or Open HTTP Server: Listening on port 80/8080
Mobile app:
- Detects device network
- Switches to device AP
- POSTs credentials to device endpoint
- Monitors status
- Switches back to home network
2. SmartConfig / ESP-Touch
How it works:
- Device enters listening mode
- App encodes credentials into WiFi packet patterns
- Device captures packets and decodes credentials
- No direct connection needed
Advantages:
- Better UX (no network switching)
- User stays on home WiFi
- Simultaneous provisioning of multiple devices
Disadvantages:
- Less reliable (packet loss issues)
- Security concerns (credentials broadcast)
- Platform-specific implementations
- Doesn’t work on all WiFi chipsets
Best for: ESP8266/ESP32-based devices in controlled environments
3. Bluetooth Low Energy (BLE) Provisioning
How it works:
- Device advertises BLE service
- App connects via BLE
- Credentials sent over BLE
- Device connects to WiFi
Advantages:
- Excellent UX
- No network switching
- Secure pairing
- Works alongside WiFi
Disadvantages:
- Requires BLE hardware
- Platform permission complexity
- Range limitations
- BLE stack overhead
Best for: Battery-powered devices, modern consumer products
4. QR Code / NFC
How it works:
- Device displays QR code or has NFC tag
- User scans with phone
- App receives pre-configured credentials or device ID
- App provisions device (via cloud or direct)
Advantages:
- Very simple UX
- Works for pre-provisioned devices
- No complex pairing
Disadvantages:
- Requires display (QR) or NFC hardware
- Still needs credential input from user
- One-way communication
Best for: Enterprise deployments, pre-configured scenarios
Platform-Specific Considerations
Android Evolution
Android 9 and Below (API ≤28)
Capabilities:
- ✅ Full programmatic WiFi control
- ✅ Silent network switching
- ✅ Scan and retrieve full network list
- ✅ Connect without user approval
APIs:
WifiManager.enableNetwork() // Just works WifiManager.addNetwork() // Silent connection WifiManager.scanResults // Full network list
Permissions:
ACCESS_COARSE_LOCATIONsufficientCHANGE_WIFI_STATE
Android 10-12 (API 29-32)
Major Changes:
- ❌
enableNetwork()deprecated/non-functional - ⚠️ System dialog REQUIRED for connections
- ⚠️ Network binding necessary
New APIs:
NetworkRequest + WifiNetworkSpecifier ConnectivityManager.requestNetwork()
Critical Requirements:
- User Approval Dialog: Cannot bypass
- System shows: “App wants to connect to [SSID]”
- User must tap “Connect” or “Allow”
- Can be confusing for users
- Network Binding:
- After connection, get
Networkobject - All communication MUST use this bound network
- Otherwise traffic routes through cellular/other WiFi
- Must use:
network.socketFactory.createSocket()
- After connection, get
- Permissions Escalated:
- Requires
ACCESS_FINE_LOCATION(not coarse) - Must be runtime-granted
- Location services must be ON
- Requires
Example Flow:
1. App calls requestNetwork() with WifiNetworkSpecifier 2. System dialog appears 3. User taps "Connect" 4. onAvailable() callback provides Network object 5. Bind process to network 6. Use network.socketFactory for all communication 7. When done, unregister callback and unbind
Android 13+ (API 33+)
Improvements:
- ✅ New
NEARBY_WIFI_DEVICESpermission - ✅ Explicitly NOT for location tracking
- ✅ Better user understanding
Permission Declaration: xml
<uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES"
android:usesPermissionFlags="neverForLocation" />
Key Benefit: User sees “Access nearby WiFi devices” instead of “Access your location” – much clearer purpose.
Why Location Permission for WiFi?
The Privacy Rationale:
WiFi SSID names can reveal physical location. For example:
- Seeing “Starbucks_5thAve” reveals you’re near that specific Starbucks
- “AcmeCorp_Building3” reveals you’re in that building
- Home network names often include addresses
Google and Apple maintain databases mapping WiFi access points to GPS coordinates. Apps could:
- Scan WiFi networks
- Cross-reference SSIDs with location database
- Track user location without GPS permission
Therefore:
- Android ≤12 requires
ACCESS_FINE_LOCATIONfor WiFi scanning - iOS requires location permission to get current SSID
- Android 13+ introduced
NEARBY_WIFI_DEVICESto separate concerns
What Requires Location Permission:
| Action | Needs Location? | Reason |
|---|---|---|
| Scan WiFi networks | ✅ Yes (Android ≤12) | Gets list of SSIDs = potential location tracking |
| Get current SSID | ✅ Yes | Reveals where you are |
| Connect to WiFi | ✅ Yes (Android 10-12) | Uses scanning internally |
| Send socket data | ❌ No | Pure network communication |
iOS Restrictions
iOS 11-13
Capabilities:
- ✅ Can connect to WiFi programmatically
- ❌ Cannot scan networks
- ⚠️ User approval dialog required
API:
NEHotspotConfiguration NEHotspotConfigurationManager.shared.apply()
Requirements:
- Entitlement:
com.apple.developer.networking.HotspotConfiguration - Location permission (seems unrelated but required)
- User must approve connection
iOS 14+
Additional Restrictions:
- Local network privacy prompt
- First socket connection triggers dialog
- Cannot get current SSID reliably without location permission AND location services ON
- More aggressive privacy protections
Prompts User Sees:
- “App would like to join WiFi network [SSID]” – for connection
- “App would like to find devices on local network” – for socket communication
iOS Limitations Summary
What iOS Can Do:
- ✅ Connect to known SSID with password
- ✅ Socket communication on local network
- ✅ Get current network (with caveats)
What iOS Cannot Do:
- ❌ Scan available WiFi networks
- ❌ Get list of nearby SSIDs
- ❌ Silent connections (always requires approval)
- ❌ Reliable SSID detection in all scenarios
Impact on UX:
- Must ask user to manually type WiFi name
- Can attempt to pre-fill current network (may fail)
- Cannot show network list like Android
- Requires more user input
Why Getting Current Network SSID is Unreliable
The “Simple” Feature That Isn’t:
Getting the user’s current WiFi network name seems trivial but is surprisingly unreliable across both platforms.
Android Reliability Issues
Permission Dependency:
- Location permission must be granted ✅
- BUT location services must be enabled in system settings
- If user has location OFF → returns null even with permission
- No way to programmatically enable location
Timing Problems:
- App must be in foreground
- Cannot get SSID from background on modern Android
- WiFi might not be fully connected yet
- Returns old/cached value immediately after connecting
Android 10+ Privacy Restrictions:
- Google heavily locked this down
- Even with all permissions, can randomly return null
- Some device manufacturers add additional blocks
- Samsung, Xiaomi, OnePlus each handle differently
Device-Specific Quirks:
- Different manufacturers = different behaviors
- Custom Android builds add restrictions
- Enterprise/MDM policies can block access
- No consistent behavior guaranteed
iOS Reliability Issues
Even More Restrictive:
iOS 13 Requirements:
- Requires location permission ✅
- App must be actively in use (not background)
- Can only get SSID for currently connected network
- No access to other network information
iOS 14+ Added Layers:
- Additional privacy framework
- Must explicitly request via
NEHotspotNetwork.fetchCurrent() - System can deny even with permission granted
- No explanation provided when denied
iOS 15+ Privacy Protection:
- Can return
nilfor “privacy reasons” - System decides arbitrarily
- No developer control
- No user override option
Practical Failure Scenarios:
- VPN Active:
- System reports VPN interface name
- Not the actual WiFi SSID
- Returns wrong or null value
- Corporate/Enterprise WiFi:
- MDM (Mobile Device Management) policies
- Can completely block SSID access
- Returns null for security reasons
- Just Connected:
- WiFi connected 1 second ago
- System cache not updated yet
- Returns old network name or null
- Background State:
- App was backgrounded
- iOS/Android revoke access
- Subsequent calls return null
- Manufacturer Variations:
- Samsung adds Knox security blocks
- Xiaomi MIUI has extra restrictions
- Each behaves unpredictably
When It Works (Best Case Scenario)
All conditions must be met:
- ✅ App in foreground
- ✅ Location services ON (system-wide)
- ✅ Location permission granted
- ✅ Connected to WiFi for 2+ seconds
- ✅ No VPN active
- ✅ Standard consumer network (not enterprise)
- ✅ All runtime permissions granted
- ✅ No MDM policies blocking
Even then: System may still return null for privacy reasons with no explanation.
Detection Success Rates (Real-World Data)
Based on field telemetry from consumer IoT products:
| Platform | Success Rate | Notes |
|---|---|---|
| Android 10-12 | ~75% | Location services OFF is #1 failure |
| Android 13+ | ~80% | Improved with NEARBY_WIFI_DEVICES |
| iOS 14-15 | ~60% | Very restrictive |
| iOS 16+ | ~70% | Slightly better |
Common failure reasons:
- Location services disabled (40% of failures)
- Background/timing issues (25%)
- VPN interference (15%)
- Enterprise/MDM blocks (10%)
- Unknown/system denial (10%)
Recommended Implementation Strategy
Treat as “Nice to Have” Feature:
Function: getCurrentNetwork() ↓ Try to detect (2 second timeout) ↓ Success? → Pre-fill text field (helpful!) Failed? → Leave field empty (user types) ↓ Either way, user can edit/change
UX Approach:
┌─────────────────────────────────────┐ │ WiFi Network │ ├─────────────────────────────────────┤ │ [Detecting...] ← Show briefly │ │ │ │ Then either: │ │ [HomeNetwork123] ← Detected! ✓ │ │ │ │ Or: │ │ [ ] ← Empty, manual │ │ Type network name │ └─────────────────────────────────────┘
Don’t Block on Detection:
- Never show “Detecting…” for more than 2 seconds
- Never require detection to succeed
- Always provide manual input option
- Never show error if detection fails (just leave empty)
Best Practice:
1. Attempt detection quietly 2. Pre-fill if successful (bonus!) 3. Fail silently if unsuccessful (not an error!) 4. User can always type/edit 5. Validate before submission
Why Major Apps Use Manual Input:
Even large companies with extensive resources default to manual input:
- Google Home devices
- Apple HomeKit accessories
- Philips Hue
- Amazon Alexa devices
- Smart thermostat manufacturers
They all: Let users type WiFi name manually because detection is too unreliable for production use.
Key Insight: Detection should be a convenience enhancement, never a core dependency.
Network Edge Cases
Captive Portals (Hotels, Airports, Coffee Shops)
The Problem:
Networks with captive portals require browser interaction (clicking “I Agree”, entering credentials, watching ads). IoT devices have:
- No browser
- No display to render login pages
- No input method to click buttons
Flow:
Device connects → Network connected ✓ Device tries internet → Redirected to captive portal Device cannot click "Accept" → Stuck, no internet access ❌
Detection Strategies:
- Check during user’s network selection:
- If user’s phone required captive portal, warn them
- Check for
NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL(Android) - Test HTTP request to known endpoint (gets redirected if portal exists)
- Pre-provisioning validation:
HTTP GET http://captive.apple.com/hotspot-detect.html Expected response: "Success" Captive portal response: Redirect or modified content
Solutions:
- Warning and Prevention (Recommended)
- Detect captive portal networks
- Warn user: “This network requires login page – device cannot access”
- Suggest alternatives (home WiFi, mobile hotspot)
- MAC Address Cloning (Hacky, Not Recommended)
- Device clones authenticated phone’s MAC address
- Network thinks device = authenticated user
- Violates ToS, unreliable, security concerns
- Travel Router
- Small portable router connects to hotel WiFi
- Router handles captive portal (user clicks on router’s admin page)
- Device connects to router’s private network
- Works but requires extra hardware
Best Practice: Explicitly document in setup instructions that captive portal networks are not supported.
Mobile Hotspots
The Temporary Solution Problem:
Mobile hotspots seem like a solution for travel/hotel scenarios, but have critical limitations:
iOS Hotspot Auto-Disconnect:
Hotspot enabled ↓ ~90 seconds of "inactivity" ↓ iOS automatically disables hotspot (battery saving) ↓ Device loses connection
What counts as inactive: Just maintaining a connection without active data transfer.
Timeline:
0:00 - User enables hotspot 0:01 - Device connects ✓ 0:02 - Provisioning complete 1:30 - iOS detects "no activity" 1:31 - iOS disables hotspot automatically 1:32 - Device offline
Android Hotspot:
- Better than iOS
- Timeout varies by manufacturer (10-30 minutes typical)
- Some allow “never timeout” setting
- Still requires phone to stay nearby and powered
Workarounds (Not Ideal):
- Device Heartbeat Packets
- Device sends periodic data (every 60s)
- Keeps hotspot “active”
- Drains battery, uses cellular data
- User Keeps Hotspot Screen Open
- iOS won’t timeout if settings screen is active
- Phone screen on = fast battery drain
- Phone unusable for other tasks
- Maximize Compatibility (iOS 16+)
- Setting helps but doesn’t prevent timeout
- Still disconnects with prolonged inactivity
When Hotspot is Valid:
- ✅ 1-2 day hotel stays
- ✅ User actively monitoring
- ✅ User understands limitations
- ❌ NOT for permanent installation
- ❌ NOT for 24/7 operation
Detection:
Identify hotspot network names:
- Patterns: “iPhone”, “AndroidAP”, “‘s iPhone”, “iPad”
- Warn user about auto-disconnect behavior
- Recommend only for temporary use
Best Practice: Show strong warnings if hotspot detected, explain auto-disconnect behavior, suggest alternatives.
Hidden SSIDs
Challenge: Some networks don’t broadcast their SSID.
Impact:
- Network won’t appear in scan results
- User must manually type exact SSID
- Higher error rate (typos)
Solution:
- Provide manual SSID input option
- Validate format before sending to device
- Show “hidden network” option explicitly
Special Characters in Credentials
Problem Characters:
- Commas:
MyNetwork,WiFi– conflicts with CSV formats - Quotes:
My"Network– breaks JSON/string parsing - Backslashes:
My\Network– escape character issues - Unicode:
家庭WiFi– encoding problems - Spaces:
My Network– trailing spaces
Solutions:
- Proper Encoding:
- URL encode for HTTP
- JSON escape for JSON APIs
- Base64 encode for binary protocols
- Validation:
- Test edge cases during development
- Validate before sending
- Clear error messages
- Length Limits:
- SSID: 32 bytes maximum
- WPA2 password: 8-63 characters
- Validate before transmission
5GHz vs 2.4GHz Networks
Device Limitation: Many IoT devices only support 2.4GHz WiFi.
Problem: User selects 5GHz network, device cannot connect.
Detection:
- Android: Check frequency in scan results (>5000 MHz = 5GHz)
- iOS: Cannot reliably detect
Solution:
- Ask device manufacturer which bands supported
- If 2.4GHz only, show warning when 5GHz selected
- Guide user to select 2.4GHz network
- Clearly label networks in UI: “MyNetwork (5GHz)” vs “MyNetwork (2.4GHz)”
Security Considerations
Credential Transmission
Threats During Provisioning:
- Man-in-the-Middle on Device Network:
- Attacker connects to device’s setup network
- Intercepts credentials sent to device
- Eavesdropping on Air:
- Credentials broadcast (SmartConfig)
- Unencrypted socket communication
Mitigation Strategies:
- TLS/HTTPS:
Use HTTPS even for local communication Device generates self-signed certificate App validates certificate fingerprint
- Encryption:
- Encrypt credentials before transmission
- Device-specific key (from QR code/label)
- Public key cryptography
- Secure Provisioning Modes:
- Device setup network uses WPA2
- Not open network
- Temporary password (from label/QR)
- Time-Limited Setup:
- Device exits setup mode after 10-15 minutes
- Prevents long-term exposure
Device Authentication
Verify it’s YOUR device:
- Physical Verification:
- QR code on device contains unique ID
- User scans, app verifies against cloud
- Prevents provisioning random devices
- Certificate Pinning:
- Device has unique certificate
- App validates before sending credentials
- Challenge-Response:
- App sends random challenge
- Device signs with private key
- App verifies signature
Post-Provisioning Security
- Secure Storage on Device:
- Encrypt WiFi credentials in device flash
- Use secure element if available
- Credential Rotation:
- Allow updating WiFi password without full reset
- API for credential updates
- Factory Reset:
- Clear all credentials
- Return to unpaired state
- Physical button + app option
User Experience Best Practices
Progressive Disclosure
Don’t overwhelm users with all steps upfront:
1. Welcome screen - "Let's set up your device" 2. Device preparation - "Press and hold setup button" 3. Connection - System handles, shows progress 4. Network selection - User picks home WiFi 5. Confirmation - "All set!"
Clear Status Indicators
Users need to know what’s happening:
Good:
"Connecting to device... ⏳" "Connected! Sending WiFi credentials... 📤" "Device is connecting to your network... ⚙️" "Success! Device is online ✅"
Bad:
"Loading..." "Please wait..." (User has no idea what step they're on)
Error Recovery
Anticipate failures:
Connection Failed:
❌ Could not connect to device Troubleshooting: - Is the device powered on? - Is the LED solid blue? (not blinking) - Are you within 30 feet of the device? [Try Again] [Manual Setup]
Wrong Password:
❌ Device could not connect to "HomeWiFi" This usually means: - WiFi password is incorrect - Network is out of range - Network is 5GHz (device requires 2.4GHz) [Edit Password] [Choose Different Network]
Manual Fallback Always Available
Never have provisioning as the ONLY option:
[Automatic Setup] ← Preferred ↓ (if fails) [Manual Setup Instructions] ↓ Step-by-step guide with screenshots
Platform-Appropriate UI
Android:
- Can show network list with signal strength
- Pre-select current network
- Show security type icons
iOS:
- Manual text entry (cannot scan)
- Attempt to pre-fill current network
- Clear validation feedback
Permission Request Timing
Bad:
App launches → Immediately asks for location permission User: "Why does this app need location??" User: Denies → App broken
Good:
App launches → Shows what device does User: Taps "Set up device" App: "To find nearby devices, we need permission to access WiFi" App: Shows permission dialog with context User: Understands why → Grants permission
System Dialog Preparation
On modern OS, system dialogs are unavoidable. Prepare users:
┌────────────────────────────────────┐ │ Next Step │ ├────────────────────────────────────┤ │ Your phone will ask permission │ │ to connect to "Device-Setup-123" │ │ │ │ Please tap "Connect" or "Allow" │ │ when prompted. │ │ │ │ [I Understand] │ └────────────────────────────────────┘
Alternative Approaches
1. Device-to-App Network List
Concept: Device scans networks and sends list to app.
Flow:
1. App connects to device's setup network 2. Device performs WiFi scan 3. Device sends network list to app via socket/HTTP 4. App displays list to user 5. User selects network and enters password 6. App sends credentials back to device
Advantages:
- Works on iOS (device does the scanning)
- Consistent UX across platforms
- Accounts for what device can actually see
Disadvantages:
- Device needs WiFi scanning capability
- More complex device firmware
- Slower (device scan + transmission time)
Implementation:
App → GET /api/scan → Device
Device performs scan (2-5 seconds)
Device → Returns JSON:
{
"networks": [
{"ssid": "HomeNetwork", "rssi": -45, "security": "WPA2"},
{"ssid": "Neighbor", "rssi": -72, "security": "WPA2"}
]
}
App displays list → User selects
App → POST /api/provision {"ssid": "...", "password": "..."}
2. Cloud-Assisted Provisioning
Flow:
1. Device connects to cloud using cellular/Ethernet 2. Device registers with unique ID 3. User logs into app, sees device waiting 4. User enters WiFi credentials in app 5. App sends to cloud 6. Cloud pushes credentials to device 7. Device switches to WiFi
Advantages:
- No complex local networking
- Works remotely
- Better for enterprise deployments
Disadvantages:
- Requires device to have cloud connectivity
- Privacy concerns (credentials through cloud)
- Requires internet for initial setup
- More infrastructure
Best for: Devices with cellular, industrial IoT, enterprise
3. Hybrid BLE + WiFi
Flow:
1. Device advertises BLE 2. App connects via BLE 3. App requests WiFi networks via BLE 4. Device scans and returns list via BLE 5. User selects, app sends credentials via BLE 6. Device connects to WiFi 7. BLE disconnects
Advantages:
- Best of both worlds
- No WiFi network switching
- Secure BLE pairing
- Works on all platforms
Disadvantages:
- Requires BLE hardware
- More complex device code
- BLE permission complexity
Best for: Battery-powered devices, smart home products
4. WPS (WiFi Protected Setup)
Flow:
“`
- User presses WPS button on router
- User presses WPS button on device
- Router and device exchange credentials automatically
Advantages:
- No app needed
- Very simple for user
- Works without phone
Disadvantages:
- Many routers don’t support WPS
- Security vulnerabilities in WPS protocol
- No mobile app control
- Declining support
Status: Deprecated by industry, not recommended
Testing and Validation
Test Matrix
Comprehensive testing requires:
Platforms:
- ✅ Android 10, 11, 12, 13, 14
- ✅ iOS 13, 14, 15, 16, 17
- ✅ Various manufacturers (Samsung, Pixel, Xiaomi for Android)
Network Types:
- ✅ WPA2 Personal
- ✅ WPA3 (if supported)
- ✅ Open networks
- ✅ Hidden SSID
- ✅ Special characters in SSID/password
- ✅ 2.4GHz and 5GHz (if device supports)
- ⚠️ Captive portals (verify detection/warning)
- ⚠️ Enterprise WPA2 (often not supported)
Edge Cases:
- ✅ Very weak signal
- ✅ Very strong signal (same building)
- ✅ Multiple devices with same SSID
- ✅ Network disappears mid-provisioning
- ✅ Wrong password
- ✅ Device reset during provisioning
- ✅ App backgrounded during provisioning
- ✅ Phone call interrupts provisioning
Automated Testing Challenges
What’s Hard to Automate:
- System permission dialogs (require user tap)
- Network switching (OS restrictions)
- BLE pairing (security features)
- Physical device interactions
What Can Be Automated:
- API endpoint testing
- Mock device responses
- Error handling paths
- State machine validation
- Security scanning
Field Testing Recommendations
- Beta Program:
- Diverse device types
- Various network configurations
- Different geographic regions
- Telemetry:
- Track success/failure rates
- Time to complete provisioning
- Common error types
- OS/device version correlation
- Support Preparation:
- Document common issues
- Troubleshooting flowcharts
- Support team training
Architecture Comparison Summary
| Approach | Complexity | UX Quality | Platform Support | Security | Recommended For |
|---|---|---|---|---|---|
| SoftAP | Medium | Fair (network switching) | Universal | Medium | General purpose |
| SmartConfig | Low | Good (no switching) | ESP devices | Low | ESP32 projects |
| BLE | High | Excellent | Modern devices | High | Consumer products |
| QR Code | Low | Good (for pre-config) | Universal | Medium | Enterprise |
| Cloud-Assisted | High | Good (remote setup) | Cellular devices | High | Industrial IoT |
| Device Scanning | Medium | Very Good | Universal | Medium | Best hybrid approach |
Platform Permission Summary
Android Requirements
| Android Version | Location Permission | WiFi Permission | Notes |
|---|---|---|---|
| ≤9 (API 28) | ACCESS_COARSE_LOCATION | CHANGE_WIFI_STATE | Full control |
| 10-12 (API 29-32) | ACCESS_FINE_LOCATION | CHANGE_WIFI_STATE + CHANGE_NETWORK_STATE | System dialog required |
| 13+ (API 33+) | – | NEARBY_WIFI_DEVICES | Better UX, clearer purpose |
iOS Requirements
| Capability | Required | Prompt Shown | Notes |
|---|---|---|---|
| Hotspot Configuration | ✅ Entitlement needed | “Join WiFi network?” | Always required |
| Local Network Access | ✅ Yes | “Find devices on network?” | iOS 14+ |
| Location (for SSID) | ✅ When in use | “Allow location?” | Often unreliable |
Conclusion
WiFi provisioning for IoT devices is far more complex than it initially appears. The “simple” task of connecting a device to WiFi requires:
- Platform expertise: Understanding Android and iOS restrictions, which evolve with every OS version
- Network knowledge: Handling edge cases like captive portals, hidden SSIDs, special characters
- Security awareness: Protecting credentials during transmission and storage
- UX design: Guiding users through unavoidable system dialogs and failures
- Testing rigor: Validating across platforms, OS versions, and network types
Key Takeaways:
- No perfect solution exists – every approach has trade-offs
- Platform restrictions dominate – especially on modern Android/iOS
- User experience is critical – provisioning is users’ first impression
- Security cannot be optional – credentials are sensitive
- Edge cases are common – captive portals, hotspots, hidden networks
- Testing is essential – works in lab ≠ works in field
- getCurrentNetwork is unreliable – treat as bonus feature, not dependency
Recommended Approach for Most Products:
- Primary: SoftAP with device-side network scanning
- Enhancement: BLE if budget allows
- Fallback: Always provide manual setup instructions
- Validation: Detect and warn about captive portals, hotspots
- Security: TLS for credential transmission, encrypted storage
- Network Detection: Attempt to pre-fill, but never depend on it
The provisioning experience can make or break an IoT product. Invest the time to handle it properly—your users (and support team) will thank you.
Additional Resources
Standards & Specifications:
- WiFi Alliance: Device Provisioning Protocol (DPP)
- Thread Group: Thread Commissioning
- Matter: Multi-admin provisioning
Platform Documentation:
- Android Connectivity APIs: developer.android.com/guide/topics/connectivity
- iOS Network Extension: developer.apple.com/documentation/networkextension
- Apple HomeKit Accessory Protocol
Security Guidelines:
- OWASP IoT Security Guidance
- NIST Cybersecurity for IoT Devices
- WiFi Alliance Security Recommendations
WiFi Provisioning out!