I've searched everywhere for the answer to this and have yet to find a definitive answer... Please help...
I have created an app that connects and bonds to a BLE device which requires a pin. The pin is pragmatically created and displayed to the user before the iOS bluetooth bonding dialog is triggered. So far, so good. If the user correctly enters the pin into the bonding dialog the phone and the BLE device are now bonded and everyone is happy.
Now the user closes the app and terminates the bluetooth connection.
When the app starts up again and the BLE device is discovered, is there any way to know that the bonding has already taken place? Basically, I don't want to re-display a pin to the user if the device has already bonded.
I'm currently saving the identifier of the BLE device and calling RetrievePeripheralsWithIdentifiers to see if the device has been connected before. This works but if the user goes to the bluetooth listing and selects "Forget this device", RetrievePeripheralsWithIdentifiers still returns ther peripheral. I've tried restarting the phone, uninstalling and reinstalling the app. Nothing seems to make iOS forget that at some point in the past, that identifier was connected...
Help!
iOS has no API whatsoever for pairing or bonding. iOS will only prompt a pairing dialog upon request from the other device or when it reads a characteristic that requires security. Your app won't even know that the pairing dialog is being shown, when pairing is complete, or when/if the current link is encrypted.
If the device is already bonded and the LTK that iOS has stored during a previous pairing process can be used (the slave also has it), then the link will automatically be encrypted and therefore no new pairing dialog will be shown.
The list about previously connected devices has nothing to do with bonded devices. It's just a list of previously known devices.
I think you are mixing up concepts a bit. Bonding essentially means "having the same Long Term Key".
So if you have two devices, and you want them to open up an encrypted connection, both devices simply check if they have a key associated with the corresponding device, and try to use this key to encrypt the messages.
This is why a device can't really check if the bond still exists. Each device can check if its own key still exists, but how would it know if the other device still has the key? As soon as one side has forgotten the key, the bond is lost.
I don't have much experience with iOS, but I assume their should be a function to get the stored Long Term Keys to check if there is an LTK associated with a Bluetooth address. Alternatively, it should be possible to
use external storage so that instead of the stack doing it for you, you can define a file where all keys are stored, and provide the stack with the key when needed. (At least, this works with other implementations.) In this case, you could directly look in the file to check if the devices have been bonded.
Note that entering the pin corresponds to the process of "pairing". The successful conduction of this procedure and the subsequent encryption of the connection does not prove that the devices are bonded. After disconnection, the pairing information is lost and the devices need to pair again - except if you have stored the key, which makes the pair a bond.
I faced a similar problem in my app, where if the user selected "Forget this device" from the settings then my app wouldn't know.
You can use retrieveConnectedPeripherals(withServices: [CBUUID]) to check if your device is connected to the OS. If yes then proceed with your other functions, else show PIN again(or whatever you want).
retrievePeripherals(withIdentifiers:) will return the device if it was connected to your OS previously.
I am doing this in my app. Hope this helps.
Related
I am creating an IOS App to connect into a Bluetooth Device using Classic Bluetooth with Mpi using ExternalAccessory Framework.
Using showBluetoothAccessoryPicker method, I can display an alert with a list of devices that allows the user to select one Device to pair.
I can perform Steps 1 -5 of my use case as below. However I not able to perform step 6
Use case:
The User picks one Device to pair. On that case, I am using showBluetoothAccessoryPicker
The App stores, into a variable, the accessory that the user picked
Turn off the Device
The App shows an alert "Connection dropped"
Turn On the Device
The App needs to reconnect with the Device automatically without needs to select it into a list.
Is there any way or method to pair a device without display a list?
As my company is a member of the Apple MFi licensing program, I asked for Apple support and I received the answer below.
"
In response to your request below, there is presently no support for implementing the bluetooth reconnection process from the device side after an existing connection has been broken. This would be an API enhancement request which you can submit using the Apple Developer feedback assistant web page - https://feedbackassistant.apple.com.
"
"
One option would be for the accessory to handle the reconnection process itself as this is a supported bluetooth option. However, I understand if for power conservation reasons, this is not supported accessory option."
It means, there is no way, yet, to implement it from the App side. if you need that, you need to do it on the Device side.
We can submit feedback for the Apple, using the Apple Developer feedback assistant web page - https://feedbackassistant.apple.com to ask them to create it
you need to make some changes in your firmware to reinitiate the connection when it identifies the connection drop. Or else you can write a method and call on connection drop in your application which keeps looking for device in proximity (with accessory info saved in your app variable) and as and when it finds, it connects using that accessory instance.
My project have a case: one account user can only log on to one device ( if user log on to app in device A, user can't log on to app in device B). My Idea is: when user login, I'll get the imei Iphone (like android) and send it with request login to server. But I can't get imei. I try with UUID, but UUID will change when re install app. Keychain does not solve the problem. Please help me.
You have to use Keychain to store Unique Id , this will not change even if user delete app
You can use any wrapper Source code to do this
here is an example
https://github.com/Joe0708/KeychainUUID
At the beginning I'd like to mention that I do not know any method that directly answers your question, especially that Apple does not allow you to read IMEI and other similar stuff due to privacy concerns. This has been answered here.
The workaround might be as follows
Take a look at the UIDevice class, especially at the identifierForVendorProperty which provides you (according to documentation ) with a device specific value.
The value of this property is the same for apps that come from the same vendor running on the same device. A different value is returned for apps on the same device that come from different vendors, and for apps on different devices regardless of vendor.
As far as i know some financial apps are secured this way to permit only one device to access the account. This however requires registering a device each time application is reinstalled.
Alternatively you can use UUID you generate within your app (first run) and then you assign it for the user online. It might take the form similar to two step verification process. Be aware however that with such restrictions user will have to be online all the time to use your app.
My app requires BLE (bluetooth low energy) to detect proximity of users' phones to one another (therefore it does not use "accessories"). I want to modify the string that is displayed when the user does not have bluetooth enabled on their iPhone (mentioned in the title).
I have tried using the .plist key "Privacy - Bluetooth Peripheral Usage Description" but this does not work. Have also scoured the internet. Help!
There does not appear to be a documented string in Apple's defined keys:
https://developer.apple.com/library/ios/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html
An alternative may be to detect if Bluetooth is on or off before trying to use it, then present your own dialog first, explaining to the user why the app needs the permission even though it isn't really connecting to accessories. Then, only once the dialog is dismissed, trigger the event that will prompt the user.
I'm writing a Today notification center widget which I want to show different information depending on whether or not the device has password lock enabled (basically I want to hide confidential information if the device is password locked). I looked around and couldn't find any good ways to do this. Has anyone been able to successfully do this?
I would not call this best practice, but it should be a workaround:
Try to access data in the keychain. If it works, the device is free, if not it's locked.
Disclaimer: There is a chance this will break in the future with changes around WatchKit. It's not documented yet, but chances are that the watch will be able to access the keychain although the device is locked.
You may be able to enable iOS Data Protection for your app and then use the applicationProtectedDataWillBecomeUnavailable and applicationProtectedDataDidBecomeAvailable methods of UIApplication to detect changes in the password lock setting.
Warning: these API's are not intended for this use, so there's always the risk that Apple will take issue with it and reject your app.
Only for iOS 8, you can use kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly protection level to find out whether or not the device is locked. This frame worked might help you out: https://github.com/liamnichols/UIDevice-PasscodeStatus
I found on the Apple website that:
Support is also provided for waking previously paired accessories that
do not automatically connect.
This would be useful for me, as the user does not need to do pairing every time before he launchs the app.
I referred to the EAAccessory Manager API, but there seems to be no such call to it.
Can anyone provide me more reference on this topic and how can I go about doing it?
This topic is explained at EAAccessoryManager Class Reference, on showBluetoothAccessoryPickerWithNameFilter:completion: that says that:
This method synchronously displays an alert containing the list of Bluetooth accessories that have been discovered by the current device and that match the specified filter (if any). The user can select an accessory from this list and pair the device to it. Pairing an accessory updates the accessory manager’s list of connected accessories and generates a corresponding connection notification.
Of course it's not enough to connect the external device successfully, because you have to do a few more steps before and after calling this method, like adding a protocol string of the external device on "Supported external accessory protocols" property of your project's plist etc, but it would be an answer to another question. Hope it helps.