Android M Camera Intent +权限错误?

sou*_*rar 65 android android-camera android-camera-intent android-permissions android-6.0-marshmallow

我正在尝试让我的应用程序为新的Android M权限更改做好准备,并发现了一些奇怪的行为.我的应用程序使用相机意图机制允许用户从相机获取图片.但是在另一个活动中需要使用具有Camera权限的摄像头本身(因为需要这个的库依赖card.io).

但是,当我尝试启动Camera意图时,只需要相机意图的活动中的M我看到以下崩溃(如果我从Manifest中删除了Camera权限,则不会发生这种情况),

> 09-25 21:57:55.260 774-8053/? I/ActivityManager: START u0
> {act=android.media.action.IMAGE_CAPTURE flg=0x3000003
> pkg=com.google.android.GoogleCamera
> cmp=com.google.android.GoogleCamera/com.android.camera.CaptureActivity
> (has clip) (has extras)} from uid 10098 on display 0 09-25
> 21:57:55.261 774-8053/? W/ActivityManager: Permission Denial: starting
> Intent { act=android.media.action.IMAGE_CAPTURE flg=0x3000003
> pkg=com.google.android.GoogleCamera
> cmp=com.google.android.GoogleCamera/com.android.camera.CaptureActivity
> (has clip) (has extras) } from null (pid=-1, uid=10098) with revoked
> permission android.permission.CAMERA 09-25 21:57:55.263 32657-32657/?
> E/ResolverActivity: Unable to launch as uid 10098 package
> com.example.me.mycamerselectapp, while running in android:ui 09-25
> 21:57:55.263 32657-32657/? E/ResolverActivity:
> java.lang.SecurityException: Permission Denial: starting Intent {
> act=android.media.action.IMAGE_CAPTURE flg=0x3000003
> pkg=com.google.android.GoogleCamera
> cmp=com.google.android.GoogleCamera/com.android.camera.CaptureActivity
> (has clip) (has extras) } from null (pid=-1, uid=10098) with revoked
> permission android.permission.CAMERA 09-25 21:57:55.263 32657-32657/?
> E/ResolverActivity:     at
> android.os.Parcel.readException(Parcel.java:1599) 09-25 21:57:55.263
> 32657-32657/? E/ResolverActivity:     at
> android.os.Parcel.readException(Parcel.java:1552) 09-25 21:57:55.263
> 32657-32657/? E/ResolverActivity:     at
> android.app.ActivityManagerProxy.startActivityAsCaller(ActivityManagerNative.java:2730)
> 09-25 21:57:55.263 32657-32657/? E/ResolverActivity:     at
> android.app.Instrumentation.execStartActivityAsCaller(Instrumentation.java:1725)
> 09-25 21:57:55.263 32657-32657/? E/ResolverActivity:     at
> android.app.Activity.startActivityAsCaller(Activity.java:4047) 09-25
> 21:57:55.263 32657-32657/? E/ResolverActivity:     at
> com.android.internal.app.ResolverActivity$DisplayResolveInfo.startAsCaller(ResolverActivity.java:983)
> 09-25 21:57:55.263 32657-32657/? E/ResolverActivity:     at
> com.android.internal.app.ResolverActivity.safelyStartActivity(ResolverActivity.java:772)
> 09-25 21:57:55.263 32657-32657/? E/ResolverActivity:     at
> com.android.internal.app.ResolverActivity.onTargetSelected(ResolverActivity.java:754)
> 09-25 21:57:55.263 32657-32657/? E/ResolverActivity:     at
> com.android.internal.app.ChooserActivity.onTargetSelected(ChooserActivity.java:305)
> 09-25 21:57:55.263 32657-32657/? E/ResolverActivity:     at
> com.android.internal.app.ResolverActivity.startSelected(ResolverActivity.java:603)
> 09-25 21:57:55.263 32657-32657/? E/ResolverActivity:     at
> com.android.internal.app.ChooserActivity.startSelected(ChooserActivity.java:310)
> 09-25 21:57:55.263 32657-32657/? E/ResolverActivity:     at
> com.android.internal.app.ChooserActivity$ChooserRowAdapter$2.onClick(ChooserActivity.java:990)
> 09-25 21:57:55.263 32657-32657/? E/ResolverActivity:     at
> android.view.View.performClick(View.java:5198) 09-25 21:57:55.263
> 32657-32657/? E/ResolverActivity:     at
> android.view.View$PerformClick.run(View.java:21147) 09-25 21:57:55.263
> 32657-32657/? E/ResolverActivity:     at
> android.os.Handler.handleCallback(Handler.java:739) 09-25 21:57:55.263
> 32657-32657/? E/ResolverActivity:     at
> android.os.Handler.dispatchMessage(Handler.java:95) 09-25 21:57:55.263
> 32657-32657/? E/ResolverActivity:     at
> android.os.Looper.loop(Looper.java:148) 09-25 21:57:55.263
> 32657-32657/? E/ResolverActivity:     at
> android.app.ActivityThread.main(ActivityThread.java:5417) 09-25
> 21:57:55.263 32657-32657/? E/ResolverActivity:     at
> java.lang.reflect.Method.invoke(Native Method) 09-25 21:57:55.263
> 32657-32657/? E/ResolverActivity:     at
> com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
> 09-25 21:57:55.263 32657-32657/? E/ResolverActivity:     at
> com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) 09-25
> 21:57:55.286 1159-1159/? I/Keyboard.Facilitator: onFinishInput() 09-25
> 21:57:55.297 32657-32676/? E/Surface: getSlotFromBufferLocked: unknown
> buffer: 0xaec352e0 09-25 21:57:55.344 325-349/? V/RenderScript:
> 0xb3693000 Launching thread(s), CPUs 4 09-25 21:57:57.290 325-349/?
> E/Surface: getSlotFromBufferLocked: unknown buffer: 0xb3f88240
Run Code Online (Sandbox Code Playgroud)

这是Android M的已知问题吗?更重要的是我该如何解决这个问题?

在清单中我有以下,

<uses-permission android:name="android.permission.CAMERA" />
Run Code Online (Sandbox Code Playgroud)

这是我用来让用户用相机点击图片和/或选择图片的代码

public static Intent openImageIntent(Context context, Uri cameraOutputFile) {

    // Camera.
    final List<Intent> cameraIntents = new ArrayList<Intent>();
    final Intent captureIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
    final PackageManager packageManager = context.getPackageManager();
    final List<ResolveInfo> listCam = packageManager.queryIntentActivities(captureIntent, 0);
    for(ResolveInfo res : listCam) {
        final String packageName = res.activityInfo.packageName;
        final Intent intent = new Intent(captureIntent);
        intent.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name));
        intent.setPackage(packageName);
        intent.putExtra(MediaStore.EXTRA_OUTPUT, cameraOutputFile);
        cameraIntents.add(intent);
    }

    // Filesystem.
    final Intent galleryIntent = new Intent();
    galleryIntent.setType("image/*");
    galleryIntent.setAction(Intent.ACTION_GET_CONTENT);

    // Chooser of filesystem options.
    final Intent chooserIntent = Intent.createChooser(galleryIntent, "Take or select pic");

    // Add the camera options.
    chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, cameraIntents.toArray(new Parcelable[]{}));
    return chooserIntent;
}
Run Code Online (Sandbox Code Playgroud)

openImageIntent()在我的活动中点击按钮.当我在我的应用程序中没有CAMERA权限时,它工作正常,但随着添加,我得到上面发布的例外.

    @Override
    public void onClick(View v) {
        Intent picCaptureIntenet = openImageIntent(MainActivity.this, getTempImageFileUri(MainActivity.this));
        try {
            startActivityForResult(picCaptureIntenet, 100);
        } catch(Exception e) {
            Toast.makeText(MainActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show();
        }
    }
Run Code Online (Sandbox Code Playgroud)

小智 80

我有同样的问题,并从谷歌找到这个文档:https: //developer.android.com/reference/android/provider/MediaStore.html#ACTION_IMAGE_CAPTURE

"注意:如果你的应用程序以M及以上为目标并声明为使用未授予的CAMERA权限,则尝试使用此操作将导致SecurityException."

这真的很奇怪.根本没有意义.该应用程序声明使用具有IMAGE_CAPTURE操作的意图的Camera权限,只需运行SecurityException.但是,如果您的应用未使用意图使用动作声明相机权限IMAGE_CAPTURE可以毫无问题地启动相机应用.

解决方法是检查应用程序是否包含清单中的相机权限,如果是,请在启动意图之前请求相机权限.

以下是检查清单中是否包含权限的方法,无论是否授予权限都无关紧要.

public boolean hasPermissionInManifest(Context context, String permissionName) {
    final String packageName = context.getPackageName();
    try {
        final PackageInfo packageInfo = context.getPackageManager()
                .getPackageInfo(packageName, PackageManager.GET_PERMISSIONS);
        final String[] declaredPermisisons = packageInfo.requestedPermissions;
        if (declaredPermisisons != null && declaredPermisisons.length > 0) {
            for (String p : declaredPermisisons) {
                if (p.equals(permissionName)) {
                    return true;
                }
            }
        }
    } catch (NameNotFoundException e) {

    }
    return false;
}
Run Code Online (Sandbox Code Playgroud)


小智 20

如果您使用的是Android M权限模型,则首先需要在运行时检查应用程序是否具有此权限,并且必须在运行时提示用户获取此权限.您在清单上定义的权限不会在安装时自动授予.

if (checkSelfPermission(Manifest.permission.CAMERA)
        != PackageManager.PERMISSION_GRANTED) {

    requestPermissions(new String[]{Manifest.permission.CAMERA},
            MY_REQUEST_CODE);
}
Run Code Online (Sandbox Code Playgroud)

MY_REQUEST_CODE是您可以定义的静态常量,它将再次用于requestPermission对话框回调.

您将需要回调对话框结果:

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == MY_REQUEST_CODE) {
        if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            // Now user should be able to use camera
        }
        else {
            // Your app will not have this permission. Turn off all functions 
            // that require this permission or it will force close like your 
            // original question
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑

从堆栈跟踪中读取,看起来Google Camera没有启用CAMERA权限.毕竟,这可能看起来像是一个向后兼容的东西.

我们假设Google Camera(或处理您的ACTION意图的任何其他应用程序)需要特定权限.

当您的应用没有CAMERA权限时,只需让Google相机使用旧版权模式即可.

但是,在您的清单中声明了CAMERA权限后,它还会强制使用Google相机(没有Android M权限模型)中的CAMERA权限来使用Android M权限模型(我认为).

这意味着使用上述方法,您需要在运行时提供您的应用程序权限,这意味着它的子任务(在本例中为Google Camera)现在也具有该权限.

  • 但是这里没有权限与意图部分https://developer.android.com/preview/features/runtime-permissions.html说如果我们使用意图来获取图像,我们不需要声明CAMERA权限吗? (2认同)
  • @ source.rar完全如此,如果没有设置Android 4和5的权限,它仍然无效.WTF谷歌? (2认同)

A.S*_*.SD 15

至于你的问题'这是M中的一个已知问题吗?' 谷歌开发人员回复了将此问题报告为错误的人.

请参阅此处:https: //code.google.com/p/android/issues/detail?id = 188073&q = label%3APriority-Medium&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars&start=100

以下是来自谷歌人的消息:"这是为了避免用户挫败他们从应用程序撤销相机权限并且应用程序仍然能够通过意图拍摄照片的行为.用户不知道在许可撤销后拍摄的照片是通过不同的机制发生的,并且会质疑权限模型的正确性.这适用于MediaStore.ACTION_IMAGE_CAPTURE,MediaStore.ACTION_VIDEO_CAPTURE和Intent.ACTION_CALL文档,其中记录针对M的应用的行为更改.

由于Google不介意从用户那里抽象出使用相机的机制,因此您可能会策略性地触发第一个相机权限请求,并引用使用相机作为请求推理的Activity的功能.如果您允许应用在用户只是尝试拍照时首先发出此权限请求,则用户可能会认为您的应用行为异常,因为拍摄照片通常不需要授予权限.


Edu*_*nis 10

如果您使用的是Google M,请转到设置 - >应用 - > 您的应用 - >并提供相应的权限.