You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Android 10系统拍照功能异常问题排查与修复求助

解决Android 10下WebView调用相机后崩溃/页面重启问题

看起来你的问题核心是Android 10的Scoped Storage限制加上Activity因系统回收重启导致状态丢失,这两个因素共同引发了崩溃和WebView页面重置的问题。下面分步骤给出具体解决方案:

1. 解决Activity重启导致的状态丢失

当你启动相机后,系统可能因为内存不足销毁你的MainActivity,拍照返回时会重建Activity,这时候你之前保存的elementIdimageUri都会变成null,后续处理必然出错。必须通过onSaveInstanceStateonRestoreInstanceState保存/恢复这些关键数据,同时保存WebView的状态避免页面重载:

保存状态

在你的MainActivity中添加:

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    // 保存相机相关的关键数据
    outState.putString("elementId", elementId);
    if (imageUri != null) {
        outState.putParcelable("imageUri", imageUri);
    }
    // 保存WebView的加载状态,避免页面重启
    webView.saveState(outState);
}

恢复状态

onCreate方法中恢复数据:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    webView = findViewById(R.id.webview);
    
    // 初始化WebView的基础配置(比如启用JS、添加JavascriptInterface等)
    
    if (savedInstanceState != null) {
        // 恢复之前的elementId和imageUri
        elementId = savedInstanceState.getString("elementId");
        imageUri = savedInstanceState.getParcelable("imageUri");
        // 恢复WebView的历史状态,无需重新加载网页
        webView.restoreState(savedInstanceState);
    } else {
        // 首次启动时加载网页
        webView.loadUrl("你的网页地址");
    }
}

2. 适配Android 10的Scoped Storage

Android 10引入了Scoped Storage,原有的MediaStore.Images.Media.getBitmap方法已经过时,且在Scoped Storage环境下可能无法正确读取图片,导致Bitmap为null。同时直接删除媒体文件的逻辑也需要调整,建议改用ContentResolver.openInputStream读取图片:

替换Bitmap获取逻辑

把你AsyncTask中doInBackground里的Bitmap获取代码替换为:

try {
    InputStream inputStream = context.getContentResolver().openInputStream(imageUri);
    bitmap = BitmapFactory.decodeStream(inputStream);
    if (inputStream != null) {
        inputStream.close();
    }
    // 删除自己插入的图片(Android 10+下有权限操作)
    context.getContentResolver().delete(imageUri, null, null);
} catch (IOException e) {
    e.printStackTrace();
}

临时兼容过渡(可选)

如果暂时不想完全适配Scoped Storage,可以在AndroidManifest.xml<application>标签中添加以下属性,强制使用旧的存储模型:

<application
    ...
    android:requestLegacyExternalStorage="true">
    ...
</application>

注意:这只是过渡方案,Android 11及以上建议完全适配Scoped Storage。

3. 替换已弃用的AsyncTask(可选)

AsyncTask在Android 11已经被正式弃用,建议改用Coroutine或者ExecutorService来处理异步任务,代码更简洁可靠:

使用Coroutine示例

// 在你的Activity中调用
CoroutineScope(Dispatchers.IO).launch {
    Bitmap bitmap = null;
    try {
        InputStream inputStream = getContentResolver().openInputStream(imageUri);
        bitmap = BitmapFactory.decodeStream(inputStream);
        if (inputStream != null) {
            inputStream.close();
        }
        getContentResolver().delete(imageUri, null, null);
    } catch (IOException e) {
        e.printStackTrace();
    }
    
    // 切回主线程处理UI和JS调用
    final Bitmap finalBitmap = bitmap;
    runOnUiThread(() -> {
        if (finalBitmap != null) {
            int width = Math.round((float) 0.2 * finalBitmap.getWidth());
            int height = Math.round((float) 0.2 * finalBitmap.getHeight());
            Bitmap newBitmap = Bitmap.createScaledBitmap(finalBitmap, width, height, false);
            String base64Image = imageHandler.convertBase64(newBitmap);
            base64Image = base64Image.replace("\n", "");
            String s1 = "url('data:image/jpeg;base64," + base64Image + "') no-repeat 0% 0% / 100% 100% white";
            
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                webView.evaluateJavascript("javascript:" + "$('[data-key=\"" + elementId + "\"] .Preview').css('background',\"" + s1 + "\");", null);
                webView.evaluateJavascript("$('[data-key=\"" + elementId + "\"] input').val(\"" + base64Image + "\")", null);
            }
        } else {
            Log.d("kiki", "null bitmap");
        }
    });
}

总结

你的崩溃大概率是因为Activity重启后imageUri/elementId为空,加上Android 10下旧的Bitmap读取方法失效导致的。按照上面的步骤,先解决状态保存问题,再适配Scoped Storage,应该就能解决崩溃和WebView重启的问题了。如果还有问题,可以尝试连接调试获取详细的崩溃日志(比如用Logcat过滤你的包名),这样能更精准定位问题。

内容的提问来源于stack exchange,提问作者kikicoder

火山引擎 最新活动