简而言之,你应该在应用程序的清单和测试项目的清单中添加相同的android:sharedUserId
,并为测试项目声明必要的权限。
这个解决方法源于Android实际上为Linux用户帐户(uid)分配权限,而不是为应用程序本身分配权限(默认情况下,每个应用程序都有自己的uid,因此看起来权限是针对每个应用程序设置的)。
然而,使用相同证书签名的应用程序可以共享相同的uid。因此,它们具有共同的权限集。例如,我可以有一个请求WRITE_EXTERNAL_STORAGE权限的应用程序A和一个请求INTERNET权限的应用程序B。A和B都由相同的证书签名(假设是调试证书)。在A和B的AndroidManifest.xml文件中,android:sharedUserId="test.shared.id"
在<manifest>
标记中声明。然后,尽管它们只声明所需权限的一部分,但A和B都可以访问网络并写入SD卡,因为权限是按uid分配的。当然,这仅适用于安装了A和B的情况。
以下是在测试项目中设置的示例。应用程序的AndroidManifest.xml:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.testproject"
android:versionCode="1"
android:versionName="1.0"
android:sharedUserId="com.example.testproject.uid">
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="16" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name">
<activity
android:name="com.example.testproject.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
这是一个测试项目的AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.testproject.test"
android:sharedUserId="com.example.testproject.uid"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="8" />
<instrumentation
android:name="android.test.InstrumentationTestRunner"
android:targetPackage="com.example.testproject" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<uses-library android:name="android.test.runner" />
</application>
</manifest>
这种解决方案的缺点是,当测试包被安装时,应用程序也能够写入外部存储。如果它意外地向存储器写入某些内容,可能会在发布时未被注意到,因为该软件包将使用不同的密钥进行签名。
关于共享UID的一些附加信息可以在http://developer.android.com/guide/topics/security/permissions.html#userid找到。
sharedUserId
自API 29起已被弃用。当我使用sharedUserId
在旧版本上安装应用程序时,也会出现错误,这意味着我无法将新版本的应用程序部署到生产环境,因为用户将无法升级。 - Sam