dpa99c / cordova-diagnostic-plugin

Cordova/Phonegap plugin to manage device settings
540 stars 361 forks source link

[iOS] Bluetooth permission is requested at app startup on iOS 13 #365

Closed dpa99c closed 5 years ago

dpa99c commented 5 years ago

I'm submitting a ... (check one with "x"):

Bug report

Current behavior: Currently the iOS implementation of the Bluetooth module initialises the native Bluetooth manager immediately on plugin initialisation and because the plugin is configured to auto-initialise on app startup then this happens immediately on app startup.

However, iOS 13 has introduced new behaviour such that a runtime permission dialog is now immediately shown when initialising the Bluetooth manager. This takes control away from plugin users as to if/when to show that dialog to users.

The Bluetooth manager must be initialised in order to detect changes to the Bluetooth state and pass them to the callback registered with registerBluetoothStateChangeHandler().

Expected behavior: The initialisation of the native Bluetooth manager should be moved to a place where it can be manually-invoked by the app using the plugin, for example when registerBluetoothStateChangeHandler() is first called. This will allow plugin users to decide if/when the permission dialog will be shown.

Steps to reproduce: Include the Bluetooth module in an iOS app build.

Environment information iOS devices running iOS 13

markerio commented 5 years ago

@dpa99c Thanks for this feedback.

However in my case, I'm not using the Bluetooth module at all. I've just upgraded to iOS 13 and I then received this Bluetooth Permission Request immediately after the first app startup.

So, I think it's not related to the modules we define in the preference property. Here is my implementation:

`

`

What do you think?

Thanks

rpragesh commented 5 years ago

Is there any fix for this? cause I need to publish an app to the appstore and for that, I need to add reasons why I am using Bluetooth in the app though I am not using it.

ghost commented 5 years ago

@rpragesh if you are not using the bluetooth for real apple may reject your app. I'm struggling with the same problem.

tamsel12 commented 5 years ago

We need to set preference as stated in document

Without bluetooth we will install the plugin.so in plugin it will be hided automatically and remove the platform and add. Check the info plist file.

ghost commented 5 years ago

We need to set preference as stated in document

Without bluetooth we will install the plugin.so in plugin it will be hided automatically and remove the platform and add. Check the info plist file.

@tamsel12 I did add the preference and re-added the plugin and the ios platform, However it didn't work. Can you give me some hint how to verify whether the plugin is added properly to the platform without the bluetooth capability?

tamsel12 commented 5 years ago

@mnenchev Pls remove the platform and add platform again and check plist file, Bluetooth permission will hide

ghost commented 5 years ago

@tamsel12 what do you mean by hidden? I've done it and only thing i can find related to bluetooth is:

NSBluetoothPeripheralUsageDescription This app requires bluetooth access to function properly.

Does this mean i still have the Bluetooth Module? I still can see it under Project/Frameworks/CoreBluetooth.framework

and when i do the build and run it on the phone it still shows the bluetooth popup.

@dpa99c can you please change it so that bluetooth popup is shown only when programmatically requested instead of by default?

Thanks

dpa99c commented 5 years ago

@mnenchev If the Bluetooth components are present it means the Bluetooth module has been installed - please see the Specifying modules documentation for how to specify modules. Note that after making any changes you will have to remove/re-add the plugin for the changes to take effect.

If you require the Bluetooth module, I will update it to request Bluetooth on demand as outlined in this issue description when I get some time.

ghost commented 5 years ago

@dpa99c Thanks, i’ve followed the guide and removed/added the plugin and the platform however it didn’t work. So i’m in a dead end.

kamilbrk commented 5 years ago

@mnenchev Please see additional information in this comment: https://github.com/dpa99c/cordova-diagnostic-plugin/issues/369#issuecomment-535921333

Specifically, the part about clearing your node_modules. I can confirm that I was able to disable this module today with latest versions of Cordova, Android/iOS platforms and this plugin.

dpa99c commented 5 years ago

@mnenchev This plugin uses the npm postinstall hook to run a script which applies the modules preference in config.xml to the plugin.xml of this plugin. It's done in this way because Cordova provides no mechanism for modularisation of plugins and the Cordova hooks lifecycle runs too late to be of any use.

The script operates on the plugin.xml in the node_modules directory of your project (i.e. node_modules/cordova.plugins.diagnostic/plugin.xml before Cordova copies it to plugins/ (i.e. plugins/cordova.plugins.diagnostic/plugin.xml ). It works by commenting out the config sections in plugin.xml for each module not specified in the preference.

If you have reinstalled the plugin after re-adding the plugin, this should make the script take effect.

However, if you are have problems with this, you can manually edit plugins/cordova.plugins.diagnostic/plugin.xml to comment out/remove the config for modules which you're not using, then re-add the iOS platform to apply the changes (cordova plugin rm ios --nosave && cordova plugin add ios --nosave).

ghost commented 5 years ago

@dpa99c my app is using cordova 6.5.0 and probably that's why it is not working for me. The diagnostic plugin version i'm getting with 6.5.0 is 3.9.2 which doesn't support module filtering, does it?

dpa99c commented 5 years ago

@mnenchev no this plugin requires a minimum of cordova@7.1.0 - you will need to update Cordova

jmelvin commented 5 years ago

I followed the modules instructions to update config.xml and then install the plugin. Bluetooth is effectively commented out in plugin.xml. However, Apple still rejects the binary. They might be searching for interfaces, regardless of comment delimiters, or commenting out does not prevent the bluetooth interfaces from getting into the binary. Also tried removing and reinstalling plugin.

Totally blocked from appstore submission until this is resolved. Please advise if there are alternate workarounds.

Platform:

$ cordova plugin ls
cordova-admobsdk 7.37.0 "Google Mobile Ads SDK for Cordova"
cordova-plugin-actionsheet 2.3.3 "ActionSheet"
cordova-plugin-admobpro 2.37.2 "AdMob Plugin Pro"
cordova-plugin-ats-rules 1.0.0 "App Transport Security Rules"
cordova-plugin-camera 4.1.0 "Camera"
cordova-plugin-console 1.1.0 "Console"
cordova-plugin-contacts 3.0.1 "Contacts"
cordova-plugin-device 2.0.3 "Device"
cordova-plugin-dialogs 2.0.2 "Notification"
cordova-plugin-extension 1.5.4 "Cordova Plugin Extension"
cordova-plugin-file 6.0.2 "File"
cordova-plugin-geolocation 4.0.2 "Geolocation"
cordova-plugin-inappbrowser 3.1.0 "InAppBrowser"
cordova-plugin-media-capture 3.0.3 "Capture"
cordova-plugin-network-information 2.0.2 "Network Information"
cordova-plugin-splashscreen 5.0.3 "Splashscreen"
cordova-plugin-whitelist 1.3.4 "Whitelist"
cordova.plugins.diagnostic 5.0.0 "Diagnostic"
phonegap-plugin-barcodescanner 8.1.0 "BarcodeScanner"
uk.co.workingedge.phonegap.plugin.launchnavigator 5.0.4 "Launch Navigator"

$ cordova platform ls
Installed platforms:
  ios 5.0.1
Available platforms: 
  android ^8.0.0
  browser ^6.0.0
  electron ^1.0.0
  osx ^5.0.0
  windows ^7.0.0

$ cordova --version
9.0.0 (cordova-lib@9.0.1)

From Apple:

ITMS-90683: Missing Purpose String in Info.plist - Your app's code references one or more APIs that access sensitive user data. The app's Info.plist file should contain a NSBluetoothAlwaysUsageDescription key with a user-facing purpose string explaining clearly and completely why your app needs the data. Starting Spring 2019, all apps submitted to the App Store that access user data are required to include a purpose string. If you're using external libraries or SDKs, they may reference APIs that require a purpose string. While your app might not use these APIs, a purpose string is still required. You can contact the developer of the library or SDK and request they release a version of their code that doesn't contain the APIs. Learn more (https://developer.apple.com/documentation/uikit/core_app/protecting_the_user_s_privacy).

After you’ve corrected the issues, you can use Xcode or Application Loader to upload a new binary to App Store Connect. 
dpa99c commented 5 years ago

@jmelvin the modules mechanism ensures no native code for unwanted modules is injected into the platform project.

ghost commented 5 years ago

@dpa99c Upgrading to newer cordova is not easy at the moment. Is there any way to manually remove/comment out some source code to exclude bluetooth with cordova 6.5.0. Thanks

dpa99c commented 5 years ago

@mnenchev you'll need to fork this repo and hack the plugin.xml to remove the unwanted modules

jmelvin commented 5 years ago

@dpa99c Unfortunately, the bluetooth native code still exists after removing/re-adding the platform...

echo "    Diagnostics"  # https://github.com/dpa99c/cordova-diagnostic-plugin.git

# Workaround:  Apple now detects Bluetooth interfaces and requires an explicit permission 
#              by the user.  To prevent this popup requesting permission, even though
#              it's never used, bluetooth interfaces must be removed from the binary.
#              The below machinations are required to effectively remove Bluetooth.

REPLACEMENT="    <preference name\=\"cordova.plugins.diagnostic.modules\" value\=\"LOCATION WIFI CAMERA MICROPHONE CONTACTS EXTERNAL\" \/>"
"${SED[@]}" -e "/<name>${APPLICATION_MOBILE_PROJECT}<\/name>/{G;s/\$/${REPLACEMENT}/;}" ${APPLICATION_CONFIG_FILE}
cordova plugin add cordova.plugins.diagnostic >> ../${LOG} 2>&1
cordova platform remove ${PLATFORM} >> ../${LOG} 2>&1
cordova platform add ${PLATFORM} >> ../${LOG} 2>&1
$ find . -name Diagnostic_Bluetooth.m
./plugins/cordova.plugins.diagnostic/src/ios/Diagnostic_Bluetooth.m
./node_modules/cordova.plugins.diagnostic/src/ios/Diagnostic_Bluetooth.m
dpa99c commented 5 years ago

@jmelvin this shows the native code is present in the plugin directories (./plugins/cordova.plugins.diagnostic and ./node_modules/cordova.plugins.diagnostic) as would be expected but it has not been deployed to ./platforms/ios/.../Diagnostic_Bluetooth.*

So if you are still getting the Apple rejection you should check that another plugin in your project is not referencing the native CoreBluetooth APIs

jmelvin commented 5 years ago

@dpa99c Indeed, the geolocation plugin also uses Bluetooth for location and nearby services. My app requires Location Services which uses Bluetooth as a source of data. Even Apple admits it uses Bluetooth to improve accuracy...

Settings > Privacy > Location Services:

Location Services uses GPS, Bluetooth, and crowd-sourced Wi-Fi hotspot and cell tower locations to determine your approximate location.

Thus, I have resubmitted my build with an updated Bluetooth permission message...

Improve location accuracy when finding nearby services

Hopefully, they approve. Thanks for being so responsive on the diagnostic plugin!

dpa99c commented 5 years ago

This has been fixed in v5.0.1

rolinger commented 5 years ago

@dpa99c Damn....this issue started plaguing me too. On iOS how do you check which permissions are required in the build? there is an option in adb to check app permissions, but I can't find one for iOS. I only find out the "other" permissions I don't require when I submit the app to the App Store. And somehow BLUETOOTH was added even though my cordova.plugins.diagnostic preference is set to to value="LOCATION NOTIFICATIONS"

jmelvin commented 5 years ago

@rollinger I have not found a way to definitively determine what permissions are required by the binary either. For Bluetooth specifically, I just searched through the cordova project code for any artifacts to use as clues...

$ find . -type f -exec grep -li bluetooth {} \;

They changed the permission policy in IOS 13.1. My first submission was rejected because my binary used Bluetooth interfaces but did not have a matching permission in info.plist. I added the permission manually in Xcode and it was rejected again as they wanted to know why I needed Bluetooth and that my permission message to the user was insufficient.

Subsequently, I walked the list of plugins I used and first found this one used Bluetooth as part of the default modules list. I successfully removed the Bluetooth module, but my binary still called for Bluetooth. I tracked it down to the geolocation plugin which uses bluetooth for location accuracy. I updated the Bluetooth permission text to "Improve location accuracy when finding nearby services" and await Apple's response. I'm hoping they don't say we can't use Bluetooth for geolocation, when their own native Location Services uses it for geolocation accuracy. That would break many many apps. I'll post their response here for posterity.

rolinger commented 5 years ago

@jmelvin - I just submitted a new version yesterday when I was notified of BLUETOOTH permissions and have been on the hunt for where its coming from. I too use geolocation but I think its coming from this plugin...I uninstalled the plugin and re-installed the latest version 5.0.1. but, aside from submitting to App Store, how can you check for iOS app permissions? With adb you can see permissions with adb shell dumpsys package com.appname. Xcode doesn't tell you either (that I can find).

rolinger commented 5 years ago

@jmelvin - go figure. Apple inconsistency strikes once again. They approved my app today even though upon initial submit it auto-detected BLUETOOTH permission without proper permission notice. I still need to get it removed because I won't be so lucky next time.

attebury commented 5 years ago

I've had the same problem while using PhoneGap Build. After adding module preferences to the config.xml file the Bluetooth module was properly commented out in the plugin.xml file, but Apple still issued the Bluetooth warning. PhoneGap does not support NPM hooks "all modules (including Bluetooth module) will be installed when using Phonegap Build."

I took the same code and used Xcode to generate an IPA which Apple processed without issuing a bluetooth warning.

jmelvin commented 5 years ago

Just for the record, Apple has finally approved my 2 apps with the BLUETOOTH module included from this plugin. The apps also use the geolocation plugin which also has a dependency on Bluetooth. The only action required is to add the following to the IOS section of the top-level config.xml...

        <config-file parent="NSBluetoothAlwaysUsageDescription" target="*-Info.plist">
            <string>Improve location accuracy when finding nearby services</string>
        </config-file>
DanielDornhardt commented 5 years ago

Hi Everyone! :)

TL;DR: Cloned the Plugin, works nicely, except I have to link (ln -s) the plugin source a few steps up in my directory tree for the build to succeed. Why? How can I fix this?


Long form prose:

I used the advice from someone in this (or another) thread about the configurable Modules Issue...

We're using Meteor to "compose" our Cordova Apps for us.

Mostly this is working fine, but the modules Issue seemed to not be easily solvable.

But I did what I learned just a few weeks ago and cloned the whole plugin to my local 'packages' - folder & changed the plugin in my cordova-plugins - file to this:

cordova.plugins.diagnostic@file://./packages/cordova-diagnostic-plugin .

Then I updated the config.xml to only include the modules we need.

So far so good! 👍

-> So I thought: Yeah, man, you're mighty clever! Time to upload the new Version of our app and call it a weekend!

But no! Thusly an error occured whilst building:

image

-> In short, he's looking for the files in the wrong directory. It should be looking either in my project dir's packages - folder or the cordova-build - folder I think, I'm not sure which; But he's looking too far up in the directory tree.

-> I managed to hack it by linking my packages dir to where the compiler expects them - but that's of course not a great solution.

So, in the end, why does this happen?

I actually think this isn't too bad a workaround for people with problems with their build setup. Maybe it could be added to the documentation somewhere?

But for that it'd be great to know how to put the right paths to the compiler as not having to link your project willy-nilly across your filesystem :)

So, is there something I can do to fix the issue with the compiler looking for the files in the wrong spot?