Espresso测试无法访问ContentProvider权限异常求助
我之前在多模块Android项目里遇到过完全一样的问题,这是仪器化测试的进程特性导致的,我来帮你拆解原因并给出可行的解决办法:
问题根源
仪器化测试会跑在一个独立的进程中,它的包名是主应用包名 + ".test"(比如你的测试进程是com.mycompany.dashboardlight.test),对应的系统UID和主应用完全不同。而你的ContentProvider设置了android:exported="false",这意味着它只允许同一UID的进程访问,所以测试进程直接访问就触发了权限拒绝。
另外你用${applicationId}作为ContentProvider authorities的一部分,测试进程的applicationId是主应用的applicationId加上.test,这会导致测试代码里访问的authorities和实际安装的ContentProvider的authorities不匹配,进一步加剧了这个问题。
解决方案
1. 固定ContentProvider的Authorities
首先把模块A中ContentProvider的authorities改成固定值,避免因applicationId变化导致的不匹配:
<provider android:name="com.mycompany.data.provider.MyProvider" android:authorities="com.mycompany.data.MyProvider" android:enabled="true" android:exported="false" />
这样不管是主应用还是测试进程,访问的目标authorities都是一致的。
2. 配置自定义签名权限
通过自定义签名权限,让测试进程能合法访问ContentProvider:
- 在模块A的
AndroidManifest.xml(<application>标签外)定义权限:<permission android:name="com.mycompany.data.permission.ACCESS_MY_PROVIDER" android:protectionLevel="signature" />protectionLevel="signature"确保只有和主应用用同一签名的应用/测试进程才能获取这个权限。 - 修改模块A中ContentProvider的配置,添加权限校验:
<provider android:name="com.mycompany.data.provider.MyProvider" android:authorities="com.mycompany.data.MyProvider" android:enabled="true" android:exported="false" android:permission="com.mycompany.data.permission.ACCESS_MY_PROVIDER" /> - 在模块B的
AndroidManifest.xml中添加权限声明:<uses-permission android:name="com.mycompany.data.permission.ACCESS_MY_PROVIDER" /> - 在测试模块的
src/androidTest/AndroidManifest.xml中也添加这个权限:<uses-permission android:name="com.mycompany.data.permission.ACCESS_MY_PROVIDER" />
3. 让测试进程运行在主应用进程(可选)
如果不想配置权限,可以让测试进程直接跑在主应用的进程里,这样UID一致就能访问exported="false"的ContentProvider:
在测试模块的src/androidTest/AndroidManifest.xml的<application>标签中添加:
<application android:process="com.mycompany.dashboardlight"> <!-- 其他测试相关配置 --> </application>
不过这种方法会降低测试的隔离性,可能影响测试结果的准确性,需要根据你的测试场景选择。
验证修改
完成上述配置后,重新编译并运行仪器化测试,Activity中的AsyncTask应该能正常访问ContentProvider,不会再抛出SecurityException了。
内容的提问来源于stack exchange,提问作者f.trajkovski

