如何在Unity Android中查找权限来源

9
注意:此问题特定于Unity3D
我在Unity项目的Plugins/Android/文件夹下有一个非常干净的android清单文件,没有任何<uses-permissions/>标签。我相信最终APK中的某些权限来自Android Player设置,例如READ_EXTERNAL_STORAGE。在我的Gear VR项目中,我看到以下行添加到最终清单中,可以在Temp/StagingArea/中访问:
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-feature android:name="android.hardware.microphone" android:required="false" />

现在,这明显是来自于我的项目中的一个插件(我有很多插件)。
我的应用程序被Oculus拒绝,原因是:
您的应用程序要求过多的用户权限,并不合适地使用了用户权限。
我发现了一个解决方法here,但我不想这样做,因为这可能会再次导致应用程序被拒绝。
那么,
有没有办法找出这个权限来自哪里?
如何确定我的脚本中是否有一些代码导致Unity包含了这个权限?
谢谢。

抱歉,我无法访问该链接,您能否发布问题的链接而不是答案的链接? - Nika Kasradze
@NikaKasradze 现在尝试一下。 - Umair M
5个回答

16

易如反掌

如果您的Unity项目是使用gradle构建的,我认为这种更简单的方法适用。如果不是,请升级一下,这是另一个原因。

此外,向一篇名为“嘿,这些权限从哪里来?”的文章致以大声喊叫。

  1. 构建您的项目
  2. 打开文件/path/to/my/project/Temp/gradleOut/build/outputs/logs/manifest-merger-release-report.txt
  3. 赚钱!
  4. 在文件中搜索您的权限名称,它将显示它来自哪里。

这是文件的一部分,我正在查找WRITE_EXTERNAL_STORAGE权限。

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

有三种方式可以向您的项目添加权限。

  1. 它们在Android清单文件中进行了指定。
  2. 它们在库中进行了指定(.aar文件)。
  3. 当您使用某个功能时,Unity会添加该权限。(已添加)

我的示例在Mac上使用命令行工具。我不知道Windows的等效物,但是可以在那里找到并运行Unix工具(使用Windows 10的Linux子系统、Cygwin、自定义二进制文件等)。

1. 查找在(未压缩的)Android清单中使用的所有权限。

cd /path/to/my/project/Assets
grep -r "uses-permission" --include "AndroidManifest.xml" .

这将在当前文件夹(.)或其任何子文件夹中查找名为AndroidManifest的所有文件(-r告诉它递归搜索),并输出包含“uses-permission”单词的任何行。

在我的当前项目中,我会得到类似于以下输出:

./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. 查找Android库所需的权限

你的项目可能包含Android库(.aar文件)和Java归档文件(.jar文件)。一些Android库包含Android清单并指定使用该库所需的权限。(我认为.jar文件实际上没有这样做,但.aar文件绝对有)。.aar和.jar文件都是.zip文件,具有不同的扩展名和特定位置的特定元数据。

运行以下命令来查找它们:

find . -iname "*.?ar" -print -exec zipgrep "uses-permission" "{}" "AndroidManifest.xml" ";" 2> /dev/null

这段代码的作用是,在当前文件夹(.)及其子文件夹中查找任何扩展名为(某些东西)a r 的文件,例如.jar或.aar (-name "*.?ar")。 然后输出归档文件的文件名(-print)。 接着运行zipgrep命令(-exec)。 Zipgrep命令被告知搜索归档文件({})中名为“AndroidManifest.xml”的文件,并输出其中包含单词“uses-permission”的行。 最后,我们将错误信息导向比特桶(2> /dev/null),以便我们不会看到有关没有 Android 清单的存档的大量错误信息。

以下是示例输出:

./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
...

文件名都以句点开头。例如,我可以看到onesignal-unity.aar设置了几个权限,几个.jar文件在内部没有任何权限,一些play services库指定了权限。

如果我需要更改某个库,则可以将.aar重命名为.zip,提取它,编辑它,压缩它,然后将其重新命名。 (更改库内部的权限不一定明智,但是可能会发生。)

3. Unity添加权限

关于这个我没有什么要补充的; 如上所述,如果您使用麦克风API,Unity将为您添加权限,以使您的应用程序正常工作。

但是,之后我意识到您可以执行以下操作:

  • 打开Android的生成设置
  • 勾选“导出项目”框
  • 导出项目并注意位置
  • 转到/my/project/export/src/main/AndroidManifest.xml。 这是Unity为android清单发出的内容(在谷歌的工具进行合并之前)。
  • 将其与Assets/plugins/Android/AndroidManifest.xml进行比较(使用您喜欢的差异工具),其中的差异来自Unity。

1
这应该是最佳答案。 - Radian Jheng

3

Unity将在构建时动态为您添加权限,如Unity Technologies的eriQue所述,这是为了防止代码故障和意外行为。

您可以使用诸如Apk-decompiler之类的工具查看新清单以及使用的权限。基于此,您可以寻找可能触发这些权限的特定功能。

某些功能(例如isGeniune)将需要多个权限,因为它将针对外部服务器进行验证。

或者,您也可以在反编译的APK中替换清单,手动更改所需的清单并重新签名。这需要一些额外的工作,但如果有适当的错误日志记录,则可能加速跟踪问题函数的过程。

更新

正如我在下面的评论中提到的那样,没有真正的方法来确定功能。但是一个快速的检查清单不会有害,但需要一些工作。

  • 您是否使用任何外部服务?

很多外部服务,比如 Google、Twitter、Facebook 的 API 和工具需要额外的权限。通常这些权限与存储/网络有关,但根据工具/API 的目的,可能还需要更多权限。

尝试使用和不使用这些工具/API 来构建您的 APK,看看是否有任何差异。

  • 您是否使用 Unity 广告?

Unity 广告本身就使用了 3 个权限,而旧版本甚至可能会使用 5 个权限。如果您正在使用他们的广告,那么您必须接受这些权限。

  • 您是否已禁用 Unity 统计信息?

您是否曾经看过 Unity 提供的那些漂亮的 统计信息?除非您禁用了它,否则您很可能也参与其中。

这些统计信息需要多个权限,因为手机将在硬件级别上进行分析并在提供的统计信息中显示。

  • 您真的在使用所有的 API / 工具 / 资源要求吗?
您可能已经包含了一些来自外部方的API、工具或任何dll,这些可能包含需要依赖项的代码。通常这些并不是100%经过净化的,并且可能包含与其功能或您所需功能无关的权限要求。
比如,某些广告服务可能想要访问用户的麦克风。但由于您没有使用他们的“OMG语音响应分析”功能,因此不需要此权限。
这些权限可以手动移除,就像我在之前的回答中所描述的那样。或者通过某种形式的自动化,例如post build marked editor脚本。 问题特定:

RECORD_AUDIO 权限会在 android 清单文件中出现,如果项目中的任何脚本调用了 Microphone 库。无论该脚本是否存在于场景中都是如此。在这种特定情况下,如果项目导入了Oculus Platform SDK(商店要求),则有几个脚本使用Microphone库。因此,如果您不使用任何音频录制功能(例如语音输入),请删除 OculusPlatform/Scripts 下面的以下文件:MicrophoneInput.cs、IMicrophone.cs、MicrophoneInputNative.cs。


感谢您的努力。我已经了解所有这些东西,并在我的问题中提到了大部分。我不需要使用任何反编译器来访问最终清单,它已经在项目目录中的Temp / StagingArea文件夹中。请尝试回答我在帖子末尾的两个问题。我特别是在谈论问题中提到的权限来源。谢谢 :) - Umair M
我正在寻找一种持久的解决方案。移除权限可能会破坏某些插件,我不想这样。我确定我根本没有进行任何录音或使用麦克风。那么为什么我甚至需要在我的项目中使用该部分代码呢?我最好删除权限源而不是仅仅删除权限。 - Umair M
@UmairM 我理解您希望拥有一个持久化的解决方案,但是对于定位来说并没有。不过,您可以通过编程方式替换清单,甚至在必要时使用 [PostBuild] 事件。这样可以使其成为一个持久性解决方案,需要一些手动操作。 - MX D

1

我发现在Unity 2021中,路径现在是:

/Library/Bee/Android/Prj/IL2CPP/Gradle/launcher/build/outputs/logs/manifest-merger-release-report.txt


1

@mx-d 是对的。我只是想再添加一种修复方法:在构建设置中,您可以勾选 Google Android Project 生成一个 Android Studio 项目。从那里,您可以使用 Android Studio 的 manifest merger 工具来覆盖权限。

问题#1:找出哪个库正在添加额外权限的唯一方法是逐个删除库,构建项目并检查 .apk 清单。不幸的是,相对于生产,Unity 并不像 Android Studio 那么灵活。

问题#2:您不能通过代码在 Unity 中添加权限(除非它是专门设计用于拼接清单文件的自定义编辑器脚本)。


请看一下我在MX-D的回答下的评论。而且在我的第二个问题中,我特别提到了需要特定权限的代码,例如isGeniuneApplication.internetReachability - Umair M

0

根据Clinton Blackmore的回答,您可能可以在manifest-merger-release-report.txt文件中跟踪它,但在某些情况下,它可能在项目文件夹的其他位置,我将列出基于主要答案、我的项目和pilcrowpipe的回答提到的路径:

path\to\my\project\Temp\gradleOut\launcher\build\outputs\logs\manifest-merger-release-report.txt

path/to/my/project/Temp/gradleOut/build/outputs/logs/manifest-merger-release-report.txt

path/to/my/project/Library/Bee/Android/Prj/IL2CPP/Gradle/launcher/build/outputs/logs/manifest-merger-release-report.txt

对于需要删除权限的人来说的额外提示!

我发现在 AndroidManifest 中使用 tools:node="remove" 属性可以移除插件在项目中添加的不必要的权限。因此,我在 Unity 项目播放器设置中启用了自定义 AndroidManifest 文件,并添加了如下行以删除多个权限:
如果您想要这样做,请在 AndroidManifest 文件的应用程序标签开始之前添加这些行(根据您的需求更改权限名称)。

 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" tools:node="remove" />

 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" tools:node="remove" />

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接