我有一个向应用程序B发送意图的应用程序A.应用程序A有一个文件提供程序并将文件共享给B.它将意图添加到意图并在B上启动服务.B有一个IntentService并处理意图。现在我想根据新的Android O策略更改B以使用JobIntentService。但是我不能从A调用startService,所以我修改了我的代码以发送显式广播。我在剪辑数据中添加了uri。但是,当我收到应用程序B的意图时,我有一个安全例外。
App A:
Uri contentUri = FileProvider.getUriForFile(this, "com.myotherapp.fileprovider",
newFile);
Intent i = new Intent(INTENT_UPDATE);
ClipData clipData = ClipData.newRawUri(at.name(), contentUri);
i.setClipData(clipData);
i.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
i.setPackage("com.myapp");
sendBroadcast(i);
App B:
@Override
public void onReceive(Context arg0, Intent arg1) {
if (MyService.INTENT_UPDATE.equals(arg1.getAction())) {
MyService.enqueueWork(arg0, arg1);
}
}
堆栈:
Process: com.myapp, PID: 7690
java.lang.RuntimeException: Unable to start receiver com.myapp.MyReceiver: java.lang.SecurityException: UID 10083 does not have permission to content://com.myotherapp.fileprovider/files/Q3hnMrF8BsOJeznpVLizkTB4H6LkI90T.csv [user 0]
at android.app.ActivityThread.handleReceiver(ActivityThread.java:3259)
at android.app.ActivityThread.-wrap17(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1677)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6540)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
Caused by: java.lang.SecurityException: UID 10083 does not have permission to content://com.myotherapp.fileprovider/files/Q3hnMrF8BsOJeznpVLizkTB4H6LkI90T.csv [user 0]
at android.os.Parcel.readException(Parcel.java:1948)
at android.os.Parcel.readException(Parcel.java:1894)
at android.app.job.IJobScheduler$Stub$Proxy.enqueue(IJobScheduler.java:211)
at android.app.JobSchedulerImpl.enqueue(JobSchedulerImpl.java:53)
at android.support.v4.app.JobIntentService$JobWorkEnqueuer.enqueueWork(JobIntentService.java:314)
at android.support.v4.app.JobIntentService.enqueueWork(JobIntentService.java:472)
at com.myapp.MyService.enqueueWork(MyService.java:41)
at com.myapp.myrec.onReceive(UpdateReceiver.java:21)
at android.app.ActivityThread.handleReceiver(ActivityThread.java:3252)
at android.app.ActivityThread.-wrap17(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1677)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6540)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
编辑:我尝试在JobInfo上使用setClipData使用JobService。无论如何它根本不起作用。
答案 0 :(得分:1)
在FileProvider
的文档中,他们说
内容URI允许您使用临时访问权限授予读写访问权限。当您创建包含内容URI的Intent时,为了将内容URI发送到客户端应用程序,您还可以调用Intent.setFlags()来添加权限。只要接收活动的堆栈处于活动状态,客户端应用程序就可以使用这些权限。对于转到服务的Intent,只要服务正在运行,权限就可用。
我的猜测是,当您退出广播接收器的onReceive
方法时,权限已经消失。
<强>解决方案:强> 事实证明,问题在于不支持广播接收器,并且您只能定位活动和服务,如文档中所述。
答案 1 :(得分:0)
好的,我发现了问题。广播接收器不接收权限,您无法调用startService
,因此在这种情况下您只有一种使用作业服务的棘手方法。我创建了一个无显示活动来转发意图:
public class ProxyActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MyService.enqueueWork(this, getIntent());
finish();
}
}
但是我不完全确定这个解决方案,因为活动每次只能发送一个意图。如果你有多个意图是一个问题。您可以将launchMode与单个实例一起使用并使用onHandleIntent(),这是一个好主意,但您不能再使用主题没有显示,并且您不知道何时可以调用finish()。
编辑:正如Ian Lake(谷歌)所解释的那样“......正如您所发现的那样,URI权限确实可以通过ClipData传递给其他组件。”当您在Api 16+上使用setData()或setDataAndType()时,系统会自动创建剪辑数据,因此这解释了它的工作原理,但单个意图的问题仍然存在。
Edit2:我找到了一个更好的解决方案,至少在我的情况下,使用brodcast接收器,但调用者使用context.grantUriPermissions()
方法。