迁移到AndroidX后文件上传模块startActivityForResult报错解决方案求助
改造代码实现(替换startActivityForResult为registerForActivityResult)
1. 新增成员变量声明
在WebviewActivity类中保留原有变量,新增Activity结果启动器:
// 原有成员变量保留 private ValueCallback<Uri[]> mUMA; private String mCM; private static final String TAG = "WebviewActivity"; // 新增Activity Result启动器,完全替代废弃的startActivityForResult private ActivityResultLauncher<Intent> fileChooserLauncher;
2. 初始化启动器(在onCreate方法中实现)
registerForActivityResult必须在Activity生命周期的onStart之前调用,直接放在onCreate原有逻辑之后即可:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 保留原有onCreate逻辑,比如setContentView、WebView初始化等 // 初始化文件选择/拍照启动器,处理返回结果 fileChooserLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> { if (result.getResultCode() != RESULT_OK || mUMA == null) { // 用户取消操作,返回空值 mUMA.onReceiveValue(null); mUMA = null; return; } Intent data = result.getData(); Uri[] resultUris = null; // 处理拍照返回场景:data为空说明拍照成功,使用预先存储的文件路径 if (data == null || data.getData() == null) { if (mCM != null) { resultUris = new Uri[]{Uri.parse(mCM)}; } } else { // 处理文件选择返回场景 String dataStr = data.getDataString(); if (dataStr != null) { resultUris = new Uri[]{Uri.parse(dataStr)}; } // 兼容多选场景(如果需要开启多选,可在文件选择Intent中加EXTRA_ALLOW_MULTIPLE参数) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { if (data.getClipData() != null) { int count = data.getClipData().getItemCount(); resultUris = new Uri[count]; for (int i = 0; i < count; i++) { resultUris[i] = data.getClipData().getItemAt(i).getUri(); } } } } mUMA.onReceiveValue(resultUris); mUMA = null; }); }
3. 修改原有onShowFileChooser方法
仅需要替换最后启动Activity的代码,同时补充高版本Uri适配逻辑:
//File manager public boolean onShowFileChooser( WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) { if (mUMA != null) { mUMA.onReceiveValue(null); } mUMA = filePathCallback; Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); if (takePictureIntent.resolveActivity(WebviewActivity.this.getPackageManager()) != null) { File photoFile = null; try { photoFile = createImageFile(); takePictureIntent.putExtra("PhotoPath", mCM); } catch (IOException ex) { Log.e(TAG, "Image file creation failed", ex); } if (photoFile != null) { mCM = "file:" + photoFile.getAbsolutePath(); // 适配Android7.0+的Uri暴露限制,必须用FileProvider生成Uri Uri photoUri; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { photoUri = FileProvider.getUriForFile(this, getPackageName() + ".fileprovider", photoFile); takePictureIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); } else { photoUri = Uri.fromFile(photoFile); } takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri); } else { takePictureIntent = null; } } Intent contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT); contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE); contentSelectionIntent.setType("*/*"); // 如需开启多选可放开下面注释 // contentSelectionIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true); Intent[] intentArray; if (takePictureIntent != null) { intentArray = new Intent[]{takePictureIntent}; } else { intentArray = new Intent[0]; } Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER); chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent); chooserIntent.putExtra(Intent.EXTRA_TITLE, "Image Chooser"); chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray); // 替换原有的startActivityForResult调用 fileChooserLauncher.launch(chooserIntent); return true; }
高版本兼容说明
- API24及以上适配:必须配置FileProvider否则会触发
FileUriExposedException崩溃,需要在AndroidManifest.xml中添加如下配置:
<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_paths" /> </provider>
同时在res/xml目录下新建file_paths.xml,路径和你createImageFile方法中存储图片的路径对应即可,示例:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-files-path name="images" path="Pictures" /> </paths>
- API29及以上适配:当前逻辑已经适配分区存储规则,不需要额外申请存储权限即可正常运行。
- API30、31兼容性:完成上述改造后,文件选择、拍照上传功能在这两个版本系统上均可正常运行。
内容的提问来源于stack exchange,提问作者Dhrubajyoti Sen
相关产品推荐
相关产品推荐

