Building the release version of my application produces a manifest with a duplicate permission. The build completes successfully, but when I go to upload the new APK to production, I get the following error:
"Upload failed
Duplicate declarations of permission android.permission.READ_EXTERNAL_STORAGE with different maxSdkVersions"
In the intermediate manifests, the release AndroidManifest has the permission in question, but it only occurs once with maxSdkVersion (see below).
myapp/build/intermediates/manifests/release/AndroidManifest.xml
...
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<android:uses-permission
android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="18" />
...
Note that READ_EXTERNAL_STORAGE is generated twice, once with the tag uses-permission and once with android:uses-permission.
This error has only occurred today; the last APK I successfully uploaded was about a week ago; no dependencies or permissions have changed in my project since that time.
What I would do:
Clean project and rebuild project (I guess you did).
Delete manually all generated files in folder "build", and rebuild the project.
Check if your different gradle files have different maxSDKVersion, and make them consistent.
Maybe this permission is included in any third library (I know you wrote you haven't, but you should have GooglePlayServices at least, and a SDK update maybe made the conflict) and you only have to remove it.
Nevertheless, I would only specify the android.permission.WRITE_EXTERNAL_STORAGE permission because it should also contains the READ_EXTERNAL_STORAGE one. If it works, maybe is not an explanation of what is happening to you but it's maybe enough.
I just ran into this issue as well. It turns out that one of the libraries that my project depends on includes the READ_EXTERNAL_STORAGE permission, but my actual project does not. Simply adding this permission to my project's manifest fixed the issue.
Cleaned and closed Android studio 10 times, maxSdkVersion is not set in my gradle files, set minSdkVersion consistently in all gradle files and nothing. The only thing that made the trick was manually deleting everything inside the Build folder and built again........problem vanished
Related
When Uploaded App in Google play getting privacy issue in pre-launch report, how to get resolve this issue.
this is as a result of automatic comparison with similar apps, if you are sure that you are using IAP correctly do not worry about it and continue and way.
Clean and Rebuild your project and Add this line in your Manifest
file.
<uses-permission
android:name="com.android.vending.BILLING"
tools:node="remove" />
Furthermore,
Delete and Clear all the Caches from the Users Profile folders located in your system .android and .gradle Located: C:\Users\DELL\.android
Update and Download the latest SDK from the SDK Manager and delete the older, unused ones.
Update Gradle Wrapper.
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-all.zip
I've fixed this by researching merged manifest, text file which located in app\build\intermediates\manifest_merge_blame_file\{flavorBuildType}\manifest-merger-blame-{flavor}-{buildType}-report.txt
In this file we can see all permissions which are available in our compiled build + library which is bring this permission to merged permission list.
You can easily find which library brings permission which invoke the warning from play market:
In my case it was unused library, so as a result I've just removed unused library.
Also anouther solution - check newest version of the library and try to update (and check permissions with new library), for example in oldest version of dji sdk there is a lot of system permissions, but in new version the list was cleanuped.
Also you can remove the permission from thrird party libraries like:
<uses-permission
android:name="com.android.vending.BILLING"
tools:node="remove" />
But in this case ^ some part of functionality can be restricted.
I added some libraries to an Android app and after upload to the Google Play Store I got this warning:
The main manifest file does not declare this permission, so I assume it comes from a library.
I then check out the source code of the previous version, which did not use this permission.
Looking at the merged manifest file in Android Studio, I still see the permission:
When I click on "Go to declaration" for this permission, it takes me to the main manifest file, which does not declare this permission.
I tried to clean and rebuild the project and restart Android Studio but the permission still shows in the merged manifest tab in Android Studio. It shows in the debug and release build variant.
Why is that?
After building your app you should be able to find a manifest merger report under app/build/outputs/logs. Among other things, this file lists the origin of every permission that has been added to the merged manifest.
Note: This question is specific to Unity3D
I have a very clean android manifest file in Unity project under Plugins/Android/ folder with no <uses-permissions/> tag at all. I believe that some permissions in final APK comes from Android Player Settings for-example READ_EXTERNAL_STORAGE. In my Gear VR project I see following lines added in final manifest which can be accessed in Temp/StagingArea/:
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-feature android:name="android.hardware.microphone" android:required="false" />
Now this is definitely coming from one of the plugins that I have in my project (I have many plugins).
My app is getting rejected from Oculus saying
Your app is asking for excessive user permissions for using user
permissions inappropriately.
I found a workaround here, but I dont want to do such a thing as this may result in app rejection once again.
So
Is there a way I can find out that where this permission is coming from?
How to find out if there is some code in my scripts which causes unity to include this permission?
Thanks
Easy Way
I think this easier approach applies if your Unity project is being built with gradle. If it isn't, here is one more reason to upgrade.
Also, a big shout-out to an article called, Hey, Where Did These Permissions Come From?)
Build Your Project
Open the file /path/to/my/project/Temp/gradleOut/build/outputs/logs/manifest-merger-release-report.txt
Profit!
Search the file for the name of your permission, and it'll show you where it came from.
Here is part of the file, where I'm looking for the WRITE_EXTERNAL_STORAGE permission.
uses-permission#android.permission.WRITE_EXTERNAL_STORAGE
ADDED from /Users/clinton/Projects/<<ProjectName>>/Temp/gradleOut/src/main/AndroidManifest.xml:7:3-79
MERGED from [gradleOut:IronSource:unspecified] /Users/clinton/Projects/<<ProjectName>>/Temp/gradleOut/IronSource/build/intermediates/bundles/default/AndroidManifest.xml:13:5-81
android:name
ADDED from /Users/clinton/Projects/<<ProjectName>>/Temp/gradleOut/src/main/AndroidManifest.xml:7:20-76
Hard Way
There are three ways permissions get added to your project.
They are specified in an Android Manifest file.
They are specified in library (a .aar file).
Unity adds the permission when you use a certain feature. (Added)
My examples use command-line tools on a Mac. I don't know Windows equivalents, but it is possible to find and run unix tools there (using the linux subsystem for windows 10, cygwin, custom binaries, etc.)
1. Find all permissions used in (uncompressed) Android Manifests.
cd /path/to/my/project/Assets
grep -r "uses-permission" --include "AndroidManifest.xml" .
This will find all files named AndroidManifest in the current folder (.) or any of its subfolders (-r tells it to search recursively) and spit out any line with the words 'uses-permission'.
In my current project, I get output something like this:
./Plugins/Android/AndroidManifest.xml: <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
./Plugins/Android/AndroidManifest.xml: <uses-permission android:name="android.permission.INTERNET" />
./Plugins/Android/AndroidManifest.xml: <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
./Plugins/Android/AndroidManifest.xml: <uses-permission
./Plugins/Android/IronSource/AndroidManifest.xml: <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
./Plugins/Android/IronSource/AndroidManifest.xml: <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
2. Find the permissions required in Android Libraries
Your project likely contains android libraries (.aar files) and java archives (.jar files). Some android libraries contain an android manifest and specify permissions needed to use the library. (I don't think .jar files actually do this, but .aar files absolutely do). Both .aar and .jar files are .zip files, with a different extension and with specific metadata in specific places.
Find them by running:
find . -iname "*.?ar" -print -exec zipgrep "uses-permission" "{}" "AndroidManifest.xml" ";" 2> /dev/null
Here's what this does.
It finds any file (in the current folder (.) and its subfolders) has an extension of (something) a r, thus .jar, or .aar (-name "*.?ar").
It outputs the archive's file name (-print).
It then runs zipgrep (-exec).
Zipgrep is told to search through any files in the archive ({}) named "AndroidManifest.xml", and output any line with the words "uses-permission".
We then pipe the errors to the bit bucket (2> /dev/null) so we don't see lots of errors about archives that don't have android manifests in them.
An example output looks like this:
./OneSignal/Platforms/Android/onesignal-unity.aar
AndroidManifest.xml: <uses-permission android:name="android.permission.INTERNET" />
AndroidManifest.xml: <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
AndroidManifest.xml: <uses-permission android:name="android.permission.WAKE_LOCK" />
AndroidManifest.xml: <uses-permission android:name="android.permission.VIBRATE" />
...
./Plugins/Android/android.arch.core.common-1.1.0.jar
./Plugins/Android/android.arch.core.runtime-1.1.0.aar
./Plugins/Android/android.arch.lifecycle.common-1.1.0.jar
...
./Plugins/Android/com.google.android.gms.play-services-gcm-11.8.0.aar
AndroidManifest.xml: <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
AndroidManifest.xml: <uses-permission android:name="android.permission.INTERNET" />
./Plugins/Android/com.google.android.gms.play-services-gcm-license-11.8.0.aar
./Plugins/Android/com.google.android.gms.play-services-iid-11.8.0.aar
AndroidManifest.xml: <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
AndroidManifest.xml: <uses-permission android:name="android.permission.INTERNET" />
./Plugins/Android/com.google.android.gms.play-services-iid-license-11.8.0.aar
...
The filenames all start with periods. I can thus see, for example, that the onesignal-unity.aar sets several permissions, several .jar files were searched with no permissions inside them, and some of the play services libraries specify permissions.
If I needed to change a library, I could rename the .aar to .zip, extract it, edit it, compress it, and rename it back. (It isn't necessarily wise to change the permissions inside a library, but possible.)
3. Unity Adds the Permission
I didn't have anything to add on this; as said above, if you use the Microphone API, Unity will add a permission for you so your app will work.
However, I've since realized that you can do the following:
bring up the Build Settings for Android
tick the 'Export Project' box
Export the project, noting the location
go to /my/project/export/src/main/AndroidManifest.xml. This is what Unity emits for the android manifest (before google's tools do all the merging).
compare it (using your favourite diff tool) to Assets/plugins/Android/AndroidManifest.xml; the differences come from Unity.
Unity will add permissions for you on the fly during build time as mentioned by eriQue of Unity Technologies this is to prevent malfunction of code, and unexpected behaviours.
You could use a tool such as this Apk-decompiler to take a look at your new manifest, and which permissions this uses. Based on that you may look for certain functions that could trigger these permissions.
Certain functions such as isGeniune will require several permissions as it will use verification against an external server.
Alternatively you can also replace your manifest in the decompiled APK, manually change out the manifest with the one intended, and resign it. This is some more grunt work, but if proper error logging is in place it might speed up the process of tracking down the problematic functions.
Update
As I mentioned in the comments below as well. There is no real way to pinpoint functions. But a quick check list can not hurt, but will require some work
Are you using any external services?
A lot of external services, think of google, twitter, facebook api's and tools require additional permissions. Usually these are storage/network related, but depending on the goals of the tool / api, it could be many more.
Try building your APK with and without the tools/apis to see if there are any differences.
Are you using unity ads?
Unity ads makes use of 3 permissions by itself, and older versions might still even make use of 5. If you are using their ads, then you will have to take these for granted.
Did you disable unity statistics?
Ever looked at those fancy stats Unity seems to be able to provide? Well, unless you disabled this, you are most likely participating in this as well.
These stats require several permissions, as the phone will be analysed on a hardware level as well as seen in the provided stats.
Are you really using all your api/tool/assets requirements?
You might have included some api's, tools or just about any dll from an external party that may or may not include code that requires dependencies. Just as often those are not 100% sanitized, and might include permission requirements not relevant to their functionality, or to the functionality that you require.
Say, some ad service might want to access a users microphone. But as you are not using their "OMG vocal response analyses" functions, this permission is not required for you.
These permissions can either be removed manually, as I earlier described in my answer. Or through some form of automation such as the post build marked editor script.
QUESTION SPECIFIC:
RECORD_AUDIO permission makes its way into android manifest file if there is a call to Microphone library in any of script in project. It doesn't matter if the script exists in scene or not. In this specific case, if Oculus Platform SDK is imported in project (which is a store requirement) there are few scripts which uses Microphone library. So if you don't use any audio recording feature e.g voice input, just remove the following files under OculusPlatform/Scripts: MicrophoneInput.cs, IMicrophone.cs, MicrophoneInputNative.cs
#mx-d is right. I just want to add another way of fixing this: in build settings you can tick the Google Android Project which will generate an Android Studio project. From there you can use Android Studio's manifest merger tool to override the permissions.
Question #1: the only way to find which library is throwing in the extra permission is to remove libraries one by one, building the project and checking the .apk manifest. Unfortunately unity is not as flexible as Android Studio production-wise.
Question #2: You can not add permissions in Unity through code (unless it's a custom editor script specifically designed for stitching up manifest files)
I found with Unity 2021 the path is now:
/Library/Bee/Android/Prj/IL2CPP/Gradle/launcher/build/outputs/logs/manifest-merger-release-report.txt
I'm trying to test using the following directory structure (which was setup by Android Studio):
I can run some tests just fine, and even the AllTests.java runs fine without the AndroidManifest.xml file even being there. The thing is, for one of my new tests, I need the android.permission.INTERNET permission. So, I added the following to the AndroidManifest.xml file located within the androidTest directory:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.core"
android:versionCode="2"
android:versionName="2.0" >
<uses-sdk android:minSdkVersion="8" />
<uses-permission android:name="android.permission.INTERNET" />
</manifest>
Unfortunately, this doesn't work. I'm still getting the following error when I run one of my tests:
E/RestAPIRequestTest﹕ Permission denied (missing INTERNET permission?)
I've tried setting the package to be com.example.core.test in my AndroidManifest.xml file (since that is what it shows up as in my Settings->Apps list), but with no joy.
I'm thinking it's not even recognizing the AndroidManifest.xml file, since the version number doesn't show in the Settings for the test app, either.
How can I inject the correct permissions for my test project?
I needed to do something similar. I created a folder named "debug" next to androidTest, which corresponds to the debug variant of the app, and put an AndroidManifest.xml with the permission in that folder. Then the permission works under test since the test app uses the debug variant. It's not ideal because it blurs the line between test and debug, which aren't quite the same thing.
I think what's happening is that the permissions in androidTest/AndroidManifest.xml are going to the test app, not the target app, although it's not 100% clear to me if there are actually two different APKs or what.
In older versions of Android Studio and the Android Gradle plugin the androidTest/AndroidManifest.xml file was ignored. This was documented at the tools.android.com site at the time.
With the Android Studio 1.0+ and Android Gradle 1.0+ plugin launch in December 2014 the AndroidManifest.xml file should now be merged with the normal main/AndroidManifest.xml files (in addition to the debug and release manifest files if they exist). More details regarding the manifest merging rules are here.
If you still run into issues or are just debugging manifest related testing issues try this
(Adapt this slightly for Windows):
Drop to a terminal
change to to your project directory
cd MyApplication
Build your project, assuming 'debug' is the build type you want to test with, but you could also be testing with 'release' or a build script defined one.
./gradlew assembleDebugTest
Then inspect your test APK manifest:
ls app/build/intermediates/manifests/test/debug/AndroidManifest.xml
View your application APK manifest:
ls app/build/intermediates/manifests/full/debug/AndroidManifest.xml
A merge output log can be found detailing the manifest merging process:
ls app/build/outputs/apk/manifest-merger-debug-report.txt
A couple of extra notes:
An instrumentation element is automatically added to your test APK's AndroidManifest.xml so you should only be adding extra activities, permissions, etc that your test APK needs.
If testing with mock locations your application APK will need the ACCESS_MOCK_LOCATION permission. You can add the permission to your debug/AndroidManifest.xml file or you can define that the test APK and the application APK should use the same userId when deployed (sharedUserId attribute in your AndroidManifest.xml).
This is a known problem.
Currently (AGP <= 3.4.X) is not supporting AndroidManifest test merging.
This is reported here: https://issuetracker.google.com/issues/127986458
and here there is the issue created by one of the Roboelectric maintainers.
The workaround as described here its near the same proposed by user3286293 and currently is the only way to have the manifest merged for testing purposes.
Hope to see a fix for AGP 3.5 or 3.6
As specified here, during instrumented tests, there are generated two .apk files. If you take a look, the smaller one it's most probably the one named app-debug-androidTest-unaligned.apk and it actually does include the provided permissions.
Inspecting the file with aapt d permissions <apk_file_path>.apk can be useful to see a list of all of them.
Now, there might be an issue with the context itself where the permission is requested. I had a similar problem, trying to write some screenshots on SD card (thus needing the WRITE_EXTERNAL_STORAGE permission).
This answer helped me to fix the problem, although I cannot fully understand why it's necessary.
In few words, you'll need to declare the same android:sharedUserId in both manifests, in order to merge the permissions when both apks are installed on the same device - that happens when tests are running.
This helped me to separate permissions needed just for testing from the one in production.
You need to define that in build.gradle file:
android {
sourceSets {
androidTest.manifest.srcFile "src/androidTest/AndroidManifest.xml"
}
}
One solution would be like build main apk and test apk in single run.
Example: ./gradlew clean :main:assembleDebug :main:assembleDebugAndroidTest.
This will create a new instrumented main application which has all extra permissions required for test application.
Recently i have used READ_PHONE_STATE permission in my app. At apk installation my phone showed me that my app needs to use Phone calls permission (inherently).
Then i removed that permission (deleted <uses-permission android:name="android.permission.READ_PHONE_STATE" /> line in manifest) and generated a new apk. While installing the new apk, phone still shows that my app needs Phone calls permission. I cleaned the project but the result is same.
How can these permissions be update?
Unlike with the java source files, changing the Manifest file alone tends not to trigger a true rebuild. Anytime you change one of your xml files, clean the project before re-deploying it.