0

我有一个应用程序 A 向应用程序 B 发送意图。应用程序 A 有一个文件提供程序并与 B 共享一个文件。它将授权添加到意图并在 B 上启动一个服务。B 有一个 IntentService 并处理意图。现在我想根据新的 Android O 策略更改 B 以使用 JobIntentService 。但是我不能从 A 调用 startService,所以我修改了我的代码以发送显式广播。我在剪辑数据中添加了 uri。但是,当我收到有关应用程序 B 的意图时,我遇到了安全异常。

应用程序 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);

应用 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。无论如何它根本不起作用。

4

2 回答 2

1

FileProvider他们的文档中说

内容 URI 允许您使用临时访问权限授予读取和写入访问权限。当您创建包含内容 URI 的 Intent 时,为了将内容 URI 发送到客户端应用程序,您还可以调用 Intent.setFlags() 来添加权限。只要接收活动的堆栈处于活动状态,客户端应用程序就可以使用这些权限。对于进入服务的意图,只要服务正在运行,权限就可用。

我的猜测是,当您退出广播接收器的onReceive方法时,权限就消失了。

解决方案: 事实证明,问题在于广播接收器不受支持,您只能定位活动和服务,如文档中所述。

于 2017-06-18T14:30:06.713 回答
1

好的,我发现了问题。广播接收器没有收到权限,您也无法调用startService,因此在这种情况下,您只有一种使用 Job 服务的棘手方法。我创建了一个无显示活动来转发意图:

public class ProxyActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        MyService.enqueueWork(this, getIntent());
        finish();
    }
}

但是我并不完全确定这个解决方案,因为活动每次只能调度一个意图。如果你有多个意图是一个问题。您可以将launchMode 与单个实例一起使用并使用onHandleIntent(),这是一个好主意,但您不能再使用无显示主题,而且您不知道何时可以调用finish()。

编辑:正如 Ian Lake (Google) 所解释的,“......正如你所发现的,URI 权限确实可以通过 ClipData 链接到其他组件。” 当您在 Api 16+ 上使用 setData() 或 setDataAndType() 时,系统会自动创建剪辑数据,因此这解释了它为什么起作用,但是单一意图的问题仍然存在。

Edit2:至少在我的情况下,我找到了一个更好的解决方案,使用广播接收器,但调用者使用context.grantUriPermissions()方法。

于 2017-06-18T16:08:03.160 回答