According to the React Native docs PermissionsAndroid.check is supposed to return a boolean that shows if the corresponding permission has been granted, but for me this is always true independently of me enabling/disabling any permission for the app I'm building.
I didn't find any issue on the React Native Github about this, so I assume that this is a more of my issue than React Native's. What am I doing wrong/missunderstanding here?
System:
React Native: 0.63
Android Emulator: Pixel 4 API 29
Example:
async function checkPermissions(): void {
const hasCameraPermission = await PermissionsAndroid.check(
PermissionsAndroid.PERMISSIONS.CAMERA
);
const hasStoragePermission = await PermissionsAndroid.check(
PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE
);
console.log(`checkPermissions camera=${JSON.stringify(hasCameraPermission, null, 2)}, storage=${JSON.stringify(hasStoragePermission, null, 2)}`);
}
The result is always checkPermissions camera=true, storage=true independently of the app having permissions enabled or disabled.
I think you are doing a wrong comparison , you should compare this
PermissionsAndroid.RESULTS.GRANTED === hasStoragePermission
PermissionsAndroid.RESULTS.GRANTED === hasStoragePermission
this will give you result that you have the permission or not
Cheers !!
I think these permissions has been filtered by google play
Note: In some cases, the permissions that you request through can affect how your application is filtered by Google Play.
If you request a hardware-related permission — CAMERA, for example — Google Play assumes that your application requires the underlying hardware feature and filters the application from devices that do not offer it.
To control filtering, always explicitly declare hardware features in elements, rather than relying on Google Play to "discover" the requirements in elements. Then, if you want to disable filtering for a particular feature, you can add a android:required="false" attribute to the declaration.
Or the permission is no longer needed
beginning with Android 4.4 (API level 19), it's no longer necessary for your app to request the WRITE_EXTERNAL_STORAGE permission
You can read the doc here
Related
I want to support MANAGE_EXTERNAL_STORAGE permission for my file manager app. I have followed the following steps to do that. I have added the following line into the manifest
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
and requested the permission on main activity using the following code:
if (Environment.isExternalStorageManager()) {
//todo when permission is granted
} else {
//request for the permission
Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
Uri uri = Uri.fromParts("package", getPackageName(), null);
intent.setData(uri);
startActivity(intent);
}
My question is not regarding acquiring the permission. It is something else. When I accidentally used my old APK for Android 10 devices with legacy support for storage access, it actually worked on the Pixel 4 emulator with Android 11 in Android Studio. It asked for the write permission (WRITE_EXTERNAL_STORAGE) while I believe that permission is no longer available on Android 11. When I went into permissions, I did not see the storage (WRITE_EXTERNAL_STORAGE) permission (which I see on Android 6-10 devices), I saw the management (MANAGE_EXTERNAL_STORAGE) permission for Android 11. How does this happen? Did the system map WRITE_EXTERNAL_STORAGE into MANAGE_EXTERNAL_STORAGE permission?
The reason I am asking is that my users who upgraded their phones from Android 10 to 11, they reported that the app (which contains the WRITE_EXTERNAL_STORAGE only) is not responding on start. How does it work for me on my emulator with Pixel 4 Android 11? Is it possible to really get the same behavior my users get? I do not have a real Android 11 device.
Thank you.
From my own experience, starting from API 30 (android 11 and above), the below permission
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
is completely ignored(but MUST be included for API 29 and below in your manifest.
Having said that, users will be promoted to manually enable scoped storage on their phone settings as long as the below permission is available on your manifest.
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
what you must note
When targeting API 30 and above, please make sure to handle External storage gracefully else OS may denied this permission and your app may crash if try/catch is not equally implemented gracefully. Snippets below
if (Environment.isExternalStorageManager()) {
//todo when permission is granted
} else {
//request for the permission here
Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
Uri uri = Uri.fromParts("package", getPackageName(), null);
intent.setData(uri);
startActivity(intent);
}
In addition, don't forget to also add android:requestLegacyExternalStorage="true" in your manifest, this will enable your app users to opt out of scoped storage (only when your target API was 29, android 10) and your user access your app with android 11 and above.
As stated here,
Apps that run on Android 11 but target Android 10 (API level 29) can still request the requestLegacyExternalStorage attribute. This flag allows apps to temporarily opt out of the changes associated with scoped storage, such as granting access to different directories and different types of media files. After you update your app to target Android 11, the system ignores the requestLegacyExternalStorage flag.
Since your old APK is targetting Android 10, having requestLegacyExternalStorage can be used by Android OS to support backward compatibility.
Android does this because all apps which do not target Android 11 will stop working all together which is a pain for all users. Why bother users that they cannot use their existing app after updating to Android 11. No one will update in that case till all devs update their app.
I upgraded firebase analytics to v18.0.2 and after that, I cannot get anymore app instance id using getAppInstanceId, I started to get null.
According docs for getAppInstanceId
Retrieves the app instance id from the service, or null if FirebaseAnalytics.ConsentType.ANALYTICS_STORAGE has been set to FirebaseAnalytics.ConsentStatus.DENIED.
I see in my logs that ANALYTICS_STORAGE is denied.
Analytics storage consent denied; will not get app instance id
I don't understand why is denied provided setConsent method states that all types are granted by default
Sets the applicable end user consent state (e.g., for device identifiers) for this app on this device. Use the consent map to specify individual consent type values. Settings are persisted across app sessions. By default consent types are set to "granted".
I'm not sure how I'm supposed to deal with this new consent feature but provided there is a public setter (setConsent) I tried to manually set the granted status. (Xamarin C# code, not native but it shouldn't be relevant)
_firebaseAnalytics.SetConsent(new Dictionary<ConsentType, ConsentStatus>
{
{ ConsentType.AnalyticsStorage, ConsentStatus.Granted }
});
It didn't make a difference.
How should I deal with this new consent feature so I can get the app instance id?
This is the list of Firebase and Google Play references (Again, it's a Xamarin app so I have Xamarin references, hopefully the translation to native world is obvious)
As mentioned under Manage consent settings, the default values for Ads/Analytics storage are determined by google_analytics_default_allow_ad_storage and google_analytics_default_allow_analytics_storage in the app's AndroidManifest.xml file.
So if those values are set to true then this would also result in a null value.
Assuming none of this applies, I see that 18.0.3 "Fixed a bug in the Google Analytics Consent API". So maybe that's the root cause.
NOTE FOR IOS: iOS 14 added a new consent dialog for access to the identifier (IDFA) and if this is declined by the user, it will not be available no matter what has been set by the developer. You can read more here.
this is the code that the docs in the googleplace but this is happend
ERROR making places detection api call: ERROR
RNGooglePlaces.getCurrentPlace()
.then((results) => alert(results))
.catch((error) => alert(error.message));
According to this GitHub issue, assuming you're using tolu360's react-native-google-places library, you should check the following:
Ensure device's GPS location is on.
Ensure you have asked for (and received) ACCESS_FINE_LOCATION permission.
Ensure you are using a real device, not an emulator.
Since you need a specific place, you need a real device with the ability to report it's location, and permission to access that information!
On line 363 of RNGooglePlacesModule.java inside the library, you can add a breakpoint to see the actual error returned by likelyPlaces.getStatus(). I suggest you do this and add any extra information into your question.
I am developing a simple app that show your current position ( latitude and longitude). I am using the functions:
- navigator.geolocation.getCurrentPosition
- navigator.geolocation.watchPosition
But I have noticed that the permission is granted without asking for permission at the user.
Is this agaist the google's rules?
If yes, how can I show a dialog that ask for the permission?
For android, You can use PermissionAndroid by importing from 'react-native'.
import { PermissionsAndroid } from 'react-native'; //
Checkout this link for more info.
For iOS, You have to fill the .plist file and it pops for permission. No need to handle it explicitly.
As per the android docs
Android apps must request permission to access sensitive user data (such as contacts and SMS), as well as certain system features (such as camera and internet)
If the device is running Android 6.0 (API level 23) or higher, and the app's targetSdkVersion is 23 or higher, the user isn't notified of any app permissions at install time. Your app must ask the user to grant the dangerous permissions at runtime.
If the device is running Android 5.1.1 (API level 22) or lower, or the app's targetSdkVersion is 22 or lower while running on any version of Android, the system automatically asks the user to grant all dangerous permissions for your app at install-time.
To grant the Permissions manually you must use PermissionsAndroid before each request which is well mentioned in this link
try {
const granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.CAMERA,
{
'title': 'Cool Photo App Camera Permission',
'message': 'Cool Photo App needs access to your camera ' +
'so you can take awesome pictures.'
}
)
if (granted === PermissionsAndroid.RESULTS.GRANTED) {
console.log("You can use the camera")
} else {
console.log("Camera permission denied")
}
} catch (err) {
console.warn(err)
}
The list of dangerous permissions are mentioned here
I think you should be looking at doing this with the react-native-permissions
Permissions.request('location', { type: 'always' }).then(response => {
this.setState({ locationPermission: response })
})
I am trying to implement the Google's Fingerprint API in my app (in my Fragment specifically). Google has given an example but it's implemented inside an Activity here.
My specific question is that the code below to check if there are enrolled fingerprints already, it is giving me an error (screenshot below):
Question --> What change do I need to do to make it work in my Fragment (as opposed to an activity like Google has)?
if (!mFingerprintManager.hasEnrolledFingerprints()) {
purchaseButton.setEnabled(false);
// This happens when no fingerprints are registered.
Toast.makeText(getActivity(),
"Go to 'Settings -> Security -> Fingerprint' and register at least one fingerprint",
Toast.LENGTH_LONG).show();
return;
}
Android 6.0 must 'ask' for permission at run time. https://developer.android.com/training/permissions/requesting.html
Dangerous permissions can give the app access to the user's
confidential data. If your app lists a normal permission in its
manifest, the system grants the permission automatically. If you list
a dangerous permission, the user has to explicitly give approval to
your app.
Even if you have <uses-permission android:name="android.permission.USE_FINGERPRINT"/> in your manifest, My understanding is that you must ask for the permission. So it looks like the error is because your app doesn't have -run time- permission to use the fingerprint manager.
(only like 90% sure of this, since I'm sticking with 5.0 for now, sorry)
Update: http://developer.android.com/reference/android/Manifest.permission.html#USE_FINGERPRINT
public static final String USE_FINGERPRINT ---------- Added in API level 23
Allows an app to use fingerprint hardware.
Protection level: normal
So it appears you shouldn't need this permission at run time.
1) Do you have the permission in your manifest?
2) You should put the following code in yours to check to see if permission is revoked/not given for some reason.
if (ContextCompat.checkSelfPermission(thisActivity,
Manifest.permission.USE_FINGERPRINT) // this might need massaged to 'android.permission.USE_FINGERPRINT'
!= PackageManager.PERMISSION_GRANTED) {
Log.d ("TEST", "You don't have permission");
}
(or something close to this) like the example from https://developer.android.com/training/permissions/requesting.html