由 java.lang.SecurityException 引起:UID 10243 没有权限 content://media/external/audio/media/5927 [user 0]

Kar*_*tik 6 android crash-reports android-notifications

我是新手 Android 开发人员,正在尝试调试我们的应用程序崩溃的原因。当我们尝试向 Android 设备发送推送通知时遇到崩溃。这是我需要解决的入职票。我不知道是什么导致了这个问题,可以在 Android N、O 和 P 中重现。我们来自 Fabric 的堆栈跟踪如下所示

Caused by java.lang.SecurityException: UID 10243 does not have permission to content://media/external/audio/media/5927 [user 0]
       at android.os.Parcel.createException + 1966(Parcel.java:1966)
       at android.os.Parcel.readException + 1934(Parcel.java:1934)
       at android.os.Parcel.readException + 1884(Parcel.java:1884)
       at android.app.INotificationManager$Stub$Proxy.enqueueNotificationWithTag + 1653(INotificationManager.java:1653)
       at android.app.NotificationManager.notifyAsUser + 429(NotificationManager.java:429)
       at android.app.NotificationManager.notify + 379(NotificationManager.java:379)
       at android.app.NotificationManager.notify + 355(NotificationManager.java:355)
       at com.myproject.mobile.notifications.NotificationHelper.process + 66(NotificationHelper.java:66)
       at com.myproject.mobile.notifications.NotificationService.constructNotification + 709(NotificationService.java:709)
       at com.myproject.mobile.notifications.NotificationService.processNotification + 173(NotificationService.java:173)
       at com.myproject.mobile.notifications.PushJobIntentService.onHandleWork + 24(PushJobIntentService.java:24)
       at androidx.core.app.JobIntentService$CommandProcessor.doInBackground + 392(JobIntentService.java:392)
       at androidx.core.app.JobIntentService$CommandProcessor.doInBackground + 383(JobIntentService.java:383)
       at android.os.AsyncTask$2.call + 333(AsyncTask.java:333)
       at java.util.concurrent.FutureTask.run + 266(FutureTask.java:266)
       at java.util.concurrent.ThreadPoolExecutor.runWorker + 1167(ThreadPoolExecutor.java:1167)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run + 641(ThreadPoolExecutor.java:641)
       at java.lang.Thread.run + 764(Thread.java:764)
Run Code Online (Sandbox Code Playgroud)

调用 NotificationManager 的代码块

public void process()
    {
        NotificationPayload payload = getPayload(); # Helper function to create a payload object. The object is a Java Bean.
        final NotificationHelper helper = new NotificationHelper(context, payloadObject);
        if (helper != null)
        {

            // Notification channels set up.
            setupChannels(context); // IntentService context.

            Notification notification = helper.buildNotification(payload); // to set up notifications.
            if (notification != null)
             NotificationManager notificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
                notificationManager.notify(payload.getNotificationId(), notification);
        }
    }
Run Code Online (Sandbox Code Playgroud)

文件提供程序 XML 文件file_provider_paths.xml

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <cache-path
        name="photos"
        path="images/" />
</paths>
Run Code Online (Sandbox Code Playgroud)

Android Manifest 中的文件提供程序定义

<provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="${applicationId}.fileProvider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_provider_paths" />
        </provider>
Run Code Online (Sandbox Code Playgroud)

来自 Fabric 的更多堆栈跟踪

Caused by android.os.RemoteException: Remote stack trace:
    at com.android.server.am.ActivityManagerService.checkGrantUriPermissionLocked(ActivityManagerService.java:12738)
    at com.android.server.am.ActivityManagerService.checkGrantUriPermission(ActivityManagerService.java:12755)
    at com.android.server.notification.NotificationRecord.visitGrantableUri(NotificationRecord.java:1147)
    at com.android.server.notification.NotificationRecord.calculateGrantableUris(NotificationRecord.java:1123)
    at com.android.server.notification.NotificationRecord.<init>(NotificationRecord.java:208)
Run Code Online (Sandbox Code Playgroud)

我提议的 PR 会在 中添加以下条目file_provider_paths.xml,但是我的 PR 被关闭了,因为审稿人的评论是

声音文件是包资源,不保存在外部存储中

<external-path
        name="external_files"
        path="." />
Run Code Online (Sandbox Code Playgroud)

更新

构建通知的构建器函数

public Notification buildNotification(NotificationPayload payload)
    {
        final NotificationCompat.Builder builder = new NotificationCompat.Builder(context, "channelId");

        final RemoteViews collapsedView = new RemoteViews(context.getPackageName(), R.layout.expanded_notification)


        if (payload.getTitle() != null)
            builder.setContentTitle(payload.getTitle());
        if (payload.getBody() != null)
            builder.setContentText(payload.getBody());

            builder.setContentIntent(payload.getClickIntent(context));

            builder.setDeleteIntent(payload.getDeleteIntent(context));


        builder.setCustomContentView(collapsedView);

        builder.setAutoCancel(true);

         builder.setSound(Uri.parse("android.resource://" + BuildConfig.APPLICATION_ID + "/" + R.raw.notif_general));
        return builder.build();
    }
Run Code Online (Sandbox Code Playgroud)

更新#2*

这就是为通知渠道设置声音的方式。

@RequiresApi(Build.VERSION_CODES.O)
@VisibleForTesting()
void setSound(Context context, NotificationChannel channel, String soundUri)
{
    AudioAttributes audioAttribute = new AudioAttributes.Builder()
        .setUsage(AudioAttributes.USAGE_NOTIFICATION)
        .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
        .build();

    channel.setSound(Uri.parse(soundUri), audioAttribute);
}
Run Code Online (Sandbox Code Playgroud)

NotificationChannel的创建

@TargetApi(26)
void registerChannel(Context context, NotificationManager notificationManager, String id, String name, String soundUri)
{
    if (notificationManager.getNotificationChannel(id) != null)
        return;

    NotificationChannel channel = new NotificationChannel(id, name, NotificationManager.IMPORTANCE_DEFAULT);

    channel.enableLights(true);
    channel.setLightColor(Color.BLUE);
    channel.enableVibration(false);

    if (soundUri != null)
    {
        setSound(context, channel, soundUri);
    }
    notificationManager.createNotificationChannel(channel);
}
Run Code Online (Sandbox Code Playgroud)

我的问题是如何解决此崩溃问题。

小智 0

请检查您的清单文件或 FileProvider

 File outputFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "Spirals"+namensss+".pdf");
                    Uri imageUri = FileProvider.getUriForFile(
                            ZoomPdf.this,
                            ".FileProvider", //(use your app signature + ".provider" )
                            outputFile);
Run Code Online (Sandbox Code Playgroud)