dotnet / android

.NET for Android provides open-source bindings of the Android SDK for use with .NET managed languages such as C#
MIT License
1.93k stars 525 forks source link

Feature Request - be able to overide permission requests of nuget or other libraries referenced #1335

Closed jzhouw closed 4 years ago

jzhouw commented 6 years ago

this request is similar to this bugzilla item https://bugzilla.xamarin.com/show_bug.cgi?id=52857 really needed this to override unneeded permission requests which added by 3rd party libraries.

bartdkmediahuis commented 6 years ago

@JonDouglas : Wondering why this is tagged as an enhancement ? This feature is available in the android-system for a long time, and not at all available when using xamarin ? Any idea when this (for us a must have) will be available ?

JonDouglas commented 6 years ago

@bartdkmediahuis Because at this time, our manifest merging does not support advance features similar to what I outlined in the Bugzilla link above. Thus we would be enhancing this feature to allow more complex merging scenarios.

We will be considering this in a future release given the 👍 count.

suggyd commented 6 years ago

For me this is critical as 3rd party libraries often request permissions for features that are not going to be used by the application.

lassana commented 6 years ago

It's not only about removing unnecessary permission declaration.

Currently I'm working on an Android Things application and I'd like to run the app on a regular phone for testing purpose. So, as the Google documentation suggests, I just added the following attribute to the manifest:

<application ... >
    <uses-library android:name="com.google.android.things" android:required="false"/>
</application>

And just look at what the manifest of the APK file contains:

<application ...>
    <uses-library
        name='com.google.android.things'
        required='false'>
    </uses-library>
    ...
    <uses-library
        name='com.google.android.things'>
    </uses-library>
</application>

I can't believe it is still not implemented in 2018, the original bug report was submitted almost 2 years ago!

markrpg commented 6 years ago

We really need full support for Androidmanifest tools. Currently as it stands if a library with permissions or metadata that needs merged or replaced, theres no easy way of achieving it. Basically makes developing Android applications with Xamarin useless unless you won't use any third party libraries, its a development environment breaking bug, not an enhancement.

BStrat77 commented 6 years ago

This is a problem for me as well, I have a NuGet package forcing the camera permission so now I can't get my app installed for devices without cameras.

rodsjo commented 5 years ago

We need this as well! We are using the Firebase Cloud Messaging (FCM) library, and it automatically injects the Xxx.Yyy.Zzz.permission.C2D_MESSAGE permission in the generated manifest. This is okay for most times, but we are experiencing that this causes the app installation to fail for thousands of our users because our Xxx.Yyy.Zzz has capital letters!

This is from a Huawei user's bug report when trying to install our app:

Bad class name Xxx.Yyy.Zzz.permission.C2D_MESSAGE in package Xxx.Yyy.Zzz

Another user reported this as well in the original GCM library

tele-bird commented 5 years ago

Not having the ability to remove permissions requested by a 3rd party library means that users of our app must accept a permission that it doesn't use. Described here: https://forums.xamarin.com/discussion/comment/360660 So, I support this feature request.

oguzhanorhaan commented 5 years ago

I need this for managing 3rd party library permissions. Unused permissions added to the AndroidManifest.

damianun commented 5 years ago

Any plans to implement Android tools for manifest merging?

MaxenceMax commented 5 years ago

you should fix this issue as fast as you can, it's a big problem for many of us

dellis1972 commented 5 years ago

That PR #3066 added the following targets AfterGenerateAndroidManifest and BeforeGenerateAndroidManifest.

AfterGenerateAndroidManifest will run directly after the internal _GenerateJavaStubs target. This is where the AndroidManifest.xml file is generated in the $(IntermediateOutputPath). So you you want to make any modifications to the generated AndroidManifest.xml file you can do this using this extension point. Documentation on how to use the new target is over at https://github.com/xamarin/xamarin-android/blob/master/Documentation/guides/BuildProcess.md#build-extension-points

While this is not a full implementation of the google manifest tooling (which will take a lot of work to implement) this does allow developers to modify the AndroidManifest.xml after it has been generated. The Unit Test added in that PR contains an example of adding xml to the AndroidManifest.xml using XmlPoke and this new entry point. See https://github.com/dellis1972/xamarin-android/blob/30f7849ec3f4deec224c2bb536affa7ce0437c31/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/ManifestTest.cs#L500.

mayhammf commented 4 years ago

Thanks @dellis1972'.

Ended up using the solution below to remove 3rd party permissions.

In the .csproj file, add the following:

<PropertyGroup>
    <AfterGenerateAndroidManifest>
      $(AfterGenerateAndroidManifest);      
      Remove3rdPartyPremisesFromAndroidManifestXML;
    </AfterGenerateAndroidManifest>
</PropertyGroup>
<Target Name="Remove3rdPartyPremisesFromAndroidManifestXML">
    <!-- Remove user permissions from AndroidManifest.xml that have the attribute tools:node="remove" (similar to how it's done by the typical android manifest merge) -->
    <!-- The transformed xml file will be temporarily placed in the folder "build-tasks" -->
    <XslTransformation
        XmlInputPaths="$(IntermediateOutputPath)android\AndroidManifest.xml"        
        XslInputPath="build-tasks\android-manifest-tools-remove-permissions.xsl"
        OutputPaths="build-tasks\AndroidManifest.xml" />
    <!-- After the transformation, copy the file "$(IntermediateOutputPath)android" to replace the original file. -->
    <Copy 
        SourceFiles="build-tasks\AndroidManifest.xml"
        DestinationFolder="$(IntermediateOutputPath)android\"/>
    <!-- Remove the temp file -->   
    <Delete Files="build-tasks\AndroidManifest.xml" />           
</Target>     

And here's the android-manifest-tools-remove-permissions.xsl which is used in the XslTransformation task

<xsl:stylesheet 
    version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:tools="http://schemas.android.com/tools" 
    xmlns:android="http://schemas.android.com/apk/res/android">

<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*" />

<xsl:variable name="removed-permissions" select=".//uses-permission[@tools:node='remove']" />

<xsl:template match="@*|node()">
 <xsl:copy>
  <xsl:apply-templates select="@*|node()"/>
 </xsl:copy>
</xsl:template>

<xsl:template match="uses-permission">
    <xsl:variable name="name" select="@android:name" />

    <xsl:if test="count($removed-permissions[@android:name = $name]) = 0">
        <xsl:copy-of select="." />
    </xsl:if>
</xsl:template>

</xsl:stylesheet>

This will work in the same way android manifest merge works, for example:

<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" tools:node="remove"/>
dellis1972 commented 4 years ago

@mayhammf Glad the extension point helped you work around this issue.

gmoney494 commented 4 years ago

A similar solutions to @mayhammf is that im using a python script set in the Android csproj options under 'Custom Command', i add a new command set "After Build". i set the command as so python remove.py ${ProjectConfig}

The script is as follows:

import os
import sys

path = "./obj/" + sys.argv[1] + "/android/"

print 'Manifest Path:',path

os.rename(path + "AndroidManifest.xml", path + "AndroidManifestOld.xml")

remove = "manifest tag to remove"

with open(path + 'AndroidManifestOld.xml') as oldfile, open(path + 'AndroidManifest.xml', 'w') as newfile:
    for line in oldfile:
        if (remove not in line):
            newfile.write(line)

os.remove(path + "AndroidManifestOld.xml")

it simply removes the line that you dont need, in my case it was an extra service tag from a 3rd party library.

dellis1972 commented 4 years ago

@gmoney494 the problem with using After Build is when you touch the manifest file you will change the timestamp, that might cause knock on effects and break the incremental build system we have.

We merged the manifest merger tooling recently, https://github.com/xamarin/xamarin-android/pull/4045 this should be available to enable in the next d16-5 preview. You can enable it by setting

<AndroidManifestMerger>manifestmerger.jar</AndroidManifestMerger>

in your csproj. You can then use the xmlns:tools="http://schemas.android.com/tools" namespace as specified here https://developer.android.com/studio/build/manifest-merge

JonDouglas commented 4 years ago

Given we now support a better AndroidManifest.xml merging tool via https://docs.microsoft.com/en-us/xamarin/android/release-notes/10/10.2#improved-android-manifest-merging

I am closing this issue as done!