为啥我无法在 Android Instant App 中访问相机?
Posted
技术标签:
【中文标题】为啥我无法在 Android Instant App 中访问相机?【英文标题】:Why can't I access camera in Android Instant App?为什么我无法在 Android Instant App 中访问相机? 【发布时间】:2018-02-18 20:04:38 【问题描述】:我正在尝试开发一个相机即时应用程序,但是当我通过manager.openCamera(cameraId, mStateCallback, null);
打开相机时它总是会崩溃:
09-10 21:00:55.333 9472-9472/com.pixelslab.stickerpe I/CameraManager: Using legacy camera HAL.
09-10 21:00:55.340 1402-1914/? I/CameraService: CameraService::connect call (PID -1 "com.pixelslab.stickerpe", camera ID 0) for HAL version default and Camera API version 1
09-10 21:00:55.340 1402-1914/? W/ServiceManager: Permission failure: android.permission.CAMERA from uid=10088 pid=9472
09-10 21:00:55.340 1402-1914/? E/CameraService: Permission Denial: can't use the camera pid=9472, uid=10088
09-10 21:00:55.345 9472-9472/com.pixelslab.stickerpe D/AndroidRuntime: Shutting down VM
09-10 21:00:55.348 9472-9472/com.pixelslab.stickerpe E/AndroidRuntime: FATAL EXCEPTION:
main Process: com.pixelslab.stickerpe, PID: 9472
java.lang.SecurityException: Lacking privileges to access camera service
at android.hardware.camera2.CameraManager.throwAsPublicException(CameraManager.java:643)
at android.hardware.camera2.CameraManager.openCameraDeviceUserAsync(CameraManager.java:340)
at android.hardware.camera2.CameraManager.openCameraForUid(CameraManager.java:466)
at android.hardware.camera2.CameraManager.openCamera(CameraManager.java:430)
at com.gomo.minivideo.camera2.Camera2VideoFragment.openCamera(Camera2VideoFragment.java:378)
at com.gomo.minivideo.camera2.Camera2VideoFragment.access$000(Camera2VideoFragment.java:65)
at com.gomo.minivideo.camera2.Camera2VideoFragment$1.onSurfaceTextureAvailable(Camera2VideoFragment.java:120)
at android.view.TextureView.getHardwareLayer(TextureView.java:390)
at android.view.TextureView.draw(TextureView.java:339)
at android.view.View.updateDisplayListIfDirty(View.java:18069)
at android.view.View.draw(View.java:18847)
at android.view.ViewGroup.drawChild(ViewGroup.java:4214)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4000)
at android.view.View.updateDisplayListIfDirty(View.java:18060)
at android.view.View.draw(View.java:18847)
at android.view.ViewGroup.drawChild(ViewGroup.java:4214)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4000)
at android.view.View.updateDisplayListIfDirty(View.java:18060)
at android.view.View.draw(View.java:18847)
at android.view.ViewGroup.drawChild(ViewGroup.java:4214)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4000)
at android.view.View.updateDisplayListIfDirty(View.java:18060)
at android.view.View.draw(View.java:18847)
at android.view.ViewGroup.drawChild(ViewGroup.java:4214)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4000)
at android.view.View.updateDisplayListIfDirty(View.java:18060)
at android.view.View.draw(View.java:18847)
at android.view.ViewGroup.drawChild(ViewGroup.java:4214)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4000)
at android.view.View.updateDisplayListIfDirty(View.java:18060)
at android.view.View.draw(View.java:18847)
at android.view.ViewGroup.drawChild(ViewGroup.java:4214)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4000)
at android.view.View.updateDisplayListIfDirty(View.java:18060)
at android.view.View.draw(View.java:18847)
at android.view.ViewGroup.drawChild(ViewGroup.java:4214)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4000)
at android.view.View.updateDisplayListIfDirty(View.java:18060)
at android.view.View.draw(View.java:18847)
at android.view.ViewGroup.drawChild(ViewGroup.java:4214)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4000)
at android.view.View.draw(View.java:19122)
at com.android.internal.policy.DecorView.draw(DecorView.java:785)
at android.view.View.updateDisplayListIfDirty(View.java:18069)
at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:643)
at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:649)
at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:757)
at android.view.ViewRootImpl.draw(ViewRootImpl.java:2980)
at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2794)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2347)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1386)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6733)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:911)
at android.view.Choreographer.doCallbacks(Choreographer.java:723)
at android.view.Choreographer.doFrame(Choreographer.java:658)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:897)
at android.os.Handler.handleCallback(Handler.java:789)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6541)
09-10 21:00:55.349 9472-9472/com.pixelslab.stickerpe E/AndroidRuntime:
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: android.os.ServiceSpecificException: Lacking privileges to access camera service (code 1)
at android.hardware.camera2.legacy.LegacyExceptionUtils.throwOnServiceError(LegacyExceptionUtils.java:132)
at android.hardware.camera2.legacy.CameraDeviceUserShim.connectBinderShim(CameraDeviceUserShim.java:374)
at android.hardware.camera2.CameraManager.openCameraDeviceUserAsync(CameraManager.java:317)
... 61 more
但是,我确信我已授予相机权限,因为相同的代码在已安装的版本中成功运行。
谁能解决这个问题?谢谢!
这是代码崩溃了:
// CameraFragment.java
private TextureView.SurfaceTextureListener mSurfaceTextureListener
= new TextureView.SurfaceTextureListener()
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture,
int width, int height)
openCamera(width, height);
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture,
int width, int height)
configureTransform(width, height);
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture)
return true;
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture)
;
private void openCamera(int width, int height)
final Activity activity = getActivity();
if (null == activity || activity.isFinishing())
return;
CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
try
Log.d(TAG, "tryAcquire");
if (!mCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS))
throw new RuntimeException("Time out waiting to lock camera opening.");
String cameraId = manager.getCameraIdList()[0];
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
StreamConfigurationMap map = characteristics
.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
mSensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
if (map == null)
throw new RuntimeException("Cannot get available preview/video sizes");
mVideoSize = chooseVideoSize(map.getOutputSizes(MediaRecorder.class));
mPreviewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class),
width, height, mVideoSize);
int orientation = getResources().getConfiguration().orientation;
if (orientation == Configuration.ORIENTATION_LANDSCAPE)
mTextureView.setAspectRatio(mPreviewSize.getWidth(), mPreviewSize.getHeight());
else
mTextureView.setAspectRatio(mPreviewSize.getHeight(), mPreviewSize.getWidth());
configureTransform(width, height);
mMediaRecorder = new MediaRecorder();
manager.openCamera(cameraId, mStateCallback, null); // here will crash!!!
catch (CameraAccessException e)
Toast.makeText(activity, "Cannot access the camera.", Toast.LENGTH_SHORT).show();
activity.finish();
catch (NullPointerException e)
ErrorDialog.newInstance(getString(R.string.camera_error))
.show(getChildFragmentManager(), FRAGMENT_DIALOG);
catch (InterruptedException e)
throw new RuntimeException("Interrupted while trying to lock camera opening.");
这是我获得相机许可的方式:
// MainActivity.java
private void requestCameraPermission()
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.CAMERA))
Snackbar.make(mRootView, R.string.permission_camera_rationale,
Snackbar.LENGTH_INDEFINITE)
.setAction(R.string.ok, new View.OnClickListener()
@Override
public void onClick(View view)
ActivityCompat.requestPermissions(MainActivity.this,
new String[]Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO, REQUEST_CAMERA);
)
.show();
else
ActivityCompat.requestPermissions(this, new String[]Manifest.permission.CAMERA,
Manifest.permission.INTERNET, Manifest.permission.RECORD_AUDIO, REQUEST_CAMERA);
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_CAMERA)
if (grantResults.length >= 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED)
getSupportFragmentManager().beginTransaction().replace(R.id.content_layout, Camera2VideoFragment.newInstance()).commitAllowingStateLoss();
//getSupportFragmentManager().beginTransaction().replace(R.id.content_layout, new CameraFragment()).commitAllowingStateLoss();
然后这是我的完整清单文件:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.pixelslab.stickerpe">
<supports-screens
android:anyDensity="true"
android:largeScreens="true"
android:normalScreens="true"
android:smallScreens="true"
android:xlargeScreens="true" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.RECORD_VIDEO" />
<uses-permission android:name="android.permission.CAMERA" />
<application
android:name="com.gomo.minivideo.CameraApp"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/CameraTheme">
<activity
android:name="com.gomo.minivideo.MainActivity"
android:configChanges="orientation|screenSize|keyboardHidden"
android:launchMode="singleTop"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="default-url"
android:value="https://hugo775128583.github.io/main" />
<intent-filter android:order="1" android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="hugo775128583.github.io"
android:pathPrefix="/main" />
</intent-filter>
<intent-filter android:order="1" android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="http"
android:host="hugo775128583.github.io"
android:pathPrefix="/main" />
</intent-filter>
</activity>
<service android:name="com.jb.zcamera.camera.ProcessVideoService" />
<activity android:name="com.gomo.minivideo.camera.ShareActivity" />
<activity android:name="com.gomo.minivideo.camera.VideoViewActivity" />
</application>
</manifest>
【问题讨论】:
我们也需要密码!没有代码无法判断发生了什么。 感谢您的建议。我刚刚发布了代码。 @JavenRuan 因此,请求权限对话框出现在您的免安装应用中,并且在您授予相机权限后,片段尝试打开相机并崩溃,但出现上述异常。那正确吗?您能否也发布您的清单文件? @Idolon,是的,你完全正确!我发布了我的清单文件,请检查。 @philo 我提交了一个错误:issuetracker.google.com/issues/66942980 【参考方案1】:参考Google issue tracker,
此问题已修复并在 8.1 设备上推出。 我们正在与我们的合作伙伴合作,将修复程序推广到 8.0 设备的更新中。 我们预计这些更新将在未来几个月内推出。
如果任何问题仍然存在,请通过Google issue tracker 报告,他们将重新打开进行检查。
【讨论】:
【参考方案2】:在清单文件中添加这一行
<uses-feature android:name="android.hardware.camera"></uses-feature>
【讨论】:
【参考方案3】:这看起来像是一个可以在 Android O 上重现的错误。它也可以通过将示例 Camera2Basic
项目改编为 Instant App 来重现:https://github.com/Idolon-V/InstantApp-Camera
我在 Google 跟踪器上提交了一个错误:https://issuetracker.google.com/issues/66942980
【讨论】:
以上是关于为啥我无法在 Android Instant App 中访问相机?的主要内容,如果未能解决你的问题,请参考以下文章
为啥 Instant 不支持 ChronoUnit.YEARS 的操作?
为啥 Instant 在彼此之后打印时显示不同的值? [关闭]
Wireless-Aruba_AP通过DHCP获取Controller地址