Instead of the interactive/runtime permissions, how can I set the permissions at install OR sticky permission so that this doesnt come up everytime I run the app.
The two permissions are LOCATION & CAMERA.
In general you request permissions in your manifest file so that the user can agree when he installs the application.
However, there has been a change recently in Android 6.0 which requires that the user is asked at runtime if the permission is dangerous. The android.permission.CAMERA permission is on of those dangerous permissions. As noted by mmBs you could set your target API level to less than Android 6.0 (e.g. 21 = 5.0) to achieve backwards compatible behaviour. But I would recommend to always update the target API level to the latest platform.
Nevertheless, you can take photos by capturing the photo using an intent (https://developer.android.com/training/camera/photobasics.html). That way your app doesn't need the CAMERA permission (the other app invoked by your intent does, but not yours).
Related
We're recreating our native iOS app in native Android, and I was told that any permissions we require inside the app must be asked upon starting the application. Is this true? I ask because we have certain activities inside the app that require mic access to use, but I'm concerned that if a user were prompted upon the application start they would (understandably) decline the permission and then be unable to use our app. Any clarity here would be very helpful.
You don't need to ask for runtime permissions at the app startup. This was only true for older android versions up to android 5.1 (API level 21).
Starting with android 6.0 (API level 23) "Dangerous permissions" or "Runtime permissions" need to be granted by the user at runtime. The best practice is to "Ask for permissions in context, when the user starts to interact with the feature that requires it" (source).
I have an Android app that requires permission to read/write from/to external storage. When the app starts, it prompts the user to allow permission for external storage (and a bunch of other services - location, camera, etc).
Here's how we do it:
ActivityCompat.requestPermissions(this, new String[]{WRITE_EXTERNAL_STORAGE, CAMERA,ACCESS_FINE_LOCATION,INTERNET,WRITE_SETTINGS,ACCESS_WIFI_STATE,READ_PHONE_STATE}, PERMISSION_REQUEST_CODE)
Now, there is also an authentication service for which we need to read from external storage. We call this authentication service during startup.
Now, problem is: When you run the app for the 1st time after install, this call to authentication service may happen often before the permission to external storage is given. Because the authentication service has no permission to external storage, it fails authentication.
Workaround we do now: manually enable permission after install and then run the app. Not a long term solution though.
I did some reading and it seems in older API's we can force the permissions to be done during apk install itself. I am on API 29. Is it possible here to prompt the user to give permissions during install itself?
I also understand that this is considered a critical service and we can't bypass permissions. Rather we cannot force permissions to be default.
What I've done for now:
Initialized the authentication service later in the code so it runs only after permissions are done.
Is there a better solution available? Like some way to either force permissions for external storage by default or some other way? From what I have read, it doesnt look possible for the latest Android version. However, if there is a way to do this, pls let me know.
Thanks,
Anand
In order to know if the user has allowed or not the application with your requested permissions, you should override onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray).
This way, you can do something like this :
if (requestCode == PERMISSION_REQUEST_CODE) {
for (elem in grantResults) {
if (elem != PackageManager.PERMISSION_GRANTED)
// Abort your feature here
}
// Do your feature here
}
If every permission has been passed you can then do what you want.
The Android Developer Documentation has a nice tutorial, more complete than I've done above, but you get the idea.
Not possible to force permission at installation time, you would need to target API level < 23 but now you need to use 28/29 to create/update apps on PlayStore. You could consider to use an alternative storage location like getCacheDir() moving files where you need later when your app has permission or just getExternalFilesDir() path where you can read/write without additional permissions.
Is it possible here to prompt the user to give permissions during install itself?
From official doc:
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.
Also:
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 (see figure 2).
In any case pay attention to this point:
Beginning with Android 6.0 (API level 23), users can revoke permissions from any app at any time, even if the app targets a lower API level.
In other word it means that today you have to check for and request permissions in your code.
Initialized the authentication service later in the code so it runs only after permissions are done.
You can use the ContextCompat.checkSelfPermission also in a Service.
When you start the service you can check if the permission is granted and avoid to fail.
You can use ActivityCompat.requestPermissions only in an Activity, but you can use the callback onRequestPermissionsResult to start your service.
Is there a better solution available?
You can't force the permission but for example your Service can check for permissions it needs and if it hasn't been granted yet, you can create a friendly notification to inform user.
Critical permissions like read/write external storage, camera, SMS, contacts, and a few others cannot be forcefully asked for prior to installation. So, they've to be asked for at runtime. The best practice is to ask for them just when they're actually needed instead of asking for them all at a time in the beginning.
If your service uses one of those permissions, you've to check for that permission every time before starting the service and then start the service only if the permission is granted. Otherwise, ask for permission, override onActivityResult and then start service only if the permission is granted.
Also, keep in mind to handle the scenario when the user marks the checkbox "Don't ask again" and denies permission. In that case, the user won't see the prompt again. So, you'll have to open permission settings using intent.
From app I gave the required permission for my app. While my app is running, I went to system settings page and revoked the permission. The app is crashing. Will we be able to handle this?.
Android 6.0 (Marshmallow, API 23) switched from an install-time permission model to a runtime permission model. Now instead of the user granting all permissions at runtime, you the developer are responsible for requesting permissions at runtime and responding appropriately.
You should begin by reading the Requesting Permissions at Run Time documentation. So that you can properly request permissions on devices running Marshmallow.
To prevent your app from crashing, you need to call ContextCompat.checkSelfPermission() to see if you have a permission before attempting to call a method that requires a permission. However, this is only half the equation since you still need to request the permission if you don't already have it.
As the guide from google states out, there are normal, dangerous and special permissions.
Dangerous are, as far as I understand, disabled as default (is this true?).
If an app declares that it needs a dangerous permission, the user has to explicitly grant the permission to the app.
Does this infect also updates or only new installs?
And what exactly is the difference between the dangerous permission and
the special permissions?
Android says for special permissions:
Special Permissions
There are a couple of permissions that don't behave like normal and dangerous permissions. SYSTEM_ALERT_WINDOW and WRITE_SETTINGS are particularly sensitive, so most apps should not use them. If an app needs one of these permissions, it must declare the permission in the manifest, and send an intent requesting the user's authorization. The system responds to the intent by showing a detailed management screen to the user.
Is that not the same like the quote above? I do not get the difference.
Thanks!
System permissions are divided into two categories, normal and dangerous:
Normal permissions do not directly risk the user's privacy. If your
app lists a normal permission in its manifest, the system grants the
permission automatically.
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.
Ques : Dangerous are, as far as I understand, disabled as default (is this true?).
Ans : Yes Dangerous permissions will be disabled by default.
Ques : Does this infect also updates or only new installs?
Ans : There are Two cases
Case 1 : App Targeting & running on API Level 23
If your app is targeting API Level 23, then all the permission which are defined in the Android Manifest will now ask for a permission when they need it.
For example, instead of giving an app access to your camera when you install it, you’ll be prompted the first time the app wants to access your camera.
Case 2 : App Designed for Older Version
Older Android apps automatically get these permissions when you install them, but you can revoke any permission you want from Settings >> Apps >> App >>App Info >> Permissions.
http://developer.android.com/training/permissions/requesting.html
Dangerous
Basically Google decided to mark some permissions dangerous (see full list here). Those permissions need to be requested actively if you want to use them, so you can't just put them in the manifest and expect everything to work, it wont. But if the user gives access once, you can use that permission for the remainder of the applications life (unless the user goes in and clicks it off inside settings).
The request will open a dialog on top of your app where the user can decide if you are allowed the permission.
Special
Special are like dangerous, except even harder to use. In order to use special you have to start an intent requesting the permission so the user goes to a Google defined activity that manages everything.
This is how it works for apps targeting Android 6.0 and onward.
I'm developing an application that going to be pr-installed (as a system app) on the firmware.
from the documentation so far about the relation between system apps, new permissions model, and the protection levels - I don't understand exactly when system app needs (if at all) to request user permission.
My problems starts when I try to use the WRITE_EXTERNAL_STORAGE permission. from the documentation I can see that it marked as "dangerous" permission.
- does "dangerous" permissions grant automatically to system apps?
when I use WRITE_EXTERNAL_STORAGE permission (as a system app) I'm getting security exception, and I don't know if it's mean that even tough my app installed as a system app - "dangerous" permissions must be requested by the user..
another point to mention:
to check the app behavior as a system app, I'm installing my application APK on the sys-priv directory (the device is rooted) of a nexus 5 running SDK preview 3. this is when I'm getting the security exception when attep to use methods requires the external storage permission..
After a lot of digging and debugging, I finally found some clue of granting runtime permission on marshmallow for system app, with a lot of inspirations in this stackoverflow ticket.
The key logic is in DefaultPermissionGrantPolicy. After systemReady, PackageManagerService checks if this user's default runtime permissions are not set yet(i.e. this is a new user), if so, PackageManagerService calls DefaultPermissionGrantPolicy.grantDefaultPermissions() to check/grant permissions:
public void grantDefaultPermissions(int userId) {
grantPermissionsToSysComponentsAndPrivApps(userId);
grantDefaultSystemHandlerPermissions(userId);
}
There are two cases that your built-in app may be automatically granted with runtime permission.
A> grantPermissionsToSysComponentsAndPrivApps -> will grant runtime permission with FLAG_PERMISSION_SYSTEM_FIXED and FLAG_PERMISSION_GRANTED_BY_DEFAULT.
if your system app has uid<10000, you will be granted with permissions for your user group.
if your system app fits all below conditions, it will be granted the permissions.
is a privilegedApp (under /system/priv-app/)
is persistent (android:persistent="true")
signed with platform signature.
B> grantDefaultSystemHandlerPermissions -> will grant runtime permission with FLAG_PERMISSION_GRANTED_BY_DEFAULT .
If your app is considered as a "default platform handler app", (i.e. your app is "expected to work out-of-the-box", like camera, dialer, SMS, calendar .etc, you can read more in method grantDefaultSystemHandlerPermissions()).
Other than that, your system application needs to ask user for granting dangerous permission, as long as it has targetSdk set to 23.
Quoting the release notes for the 2nd M preview:
Apps included in the system image are no longer granted dangerous permissions automatically. All apps should check for and request permissions at runtime.
That fits with what I recall seeing when I first used the stock Camera app on a Nexus 5 with the final(?) 6.0 preview firmware — it too asked for the runtime permission.
So, AFAIK, system apps have to ask for runtime permissions, as do non-system apps.