今天在复用之前写的安装APK的相关代码时发生了报错,那是因为安卓高版本需要新增FileProvider
新增file_paths
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<!-- <root-path
name="root"
path="" />-->
<files-path
name="files"
path="files" />
<cache-path
name="cache"
path="files" />
<!-- <external-path
name="external"
path="files" />-->
<external-files-path
name="externalfiles"
path="files" />
<!-- 此标签需要 support 25.0.0以上才可以使用-->
<external-cache-path
name="externalcache"
path="files" />
<external-path
name="external_storage_root"
path="." />
</paths>
其他写法
<root-path name="root" path="."/>
<files-path name="files" path="." />
<cache-path name="cache" path="." />
<external-path name="external" path="." />
<external-files-path name="name" path="path" />
<external-cache-path name="name" path="path" />
标签对应的地址
<files-path name="name" path="path" /> 物理路径相当于Context.getFilesDir() + /path/
<cache-path name="name" path="path" /> 物理路径相当于Context.getCacheDir() + /path/
<external-path name="name" path="path"/>
物理路径相当于Environment.getExternalStorageDirectory() + /path/
<external-files-path name="name" path="path" />
物理路径相当于**Context.getExternalFilesDir(String) **+ /path/
<external-cache-path name="name" path="path" />
物理路径相当于Context.getExternalCacheDir() + /path/
<root-path name="name" path="path" /> 物理路径相当于/path/
举例:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<!-- /storage/emulated/0/Android/data/com.test.dust/files/resources/map/tiles/1.0.8.rar
===> content://com.test.dust.provider/map_tiles/1.0.8.rar-->
<external-files-path
name="map_tiles"
path="resources/map/tiles" />
</paths>
external-files-path对应的文件路径为/storage/emulated/0/Android/data/[packageName]/files
整个external-files-path标签的作用相当于把绝对路径/storage/emulated/0/Android/data/[packageName]/files/[path]/filename格式化为content://[authorities]/[name]/filename的形式。
新增provider
在Manifest.xml的<application>中新增如下代码
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.utilcode.fileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
引用
APK安装
public static void installApk(Context context,String downloadApk) {
Intent intent = new Intent(Intent.ACTION_VIEW);
File file = new File(downloadApk);
//L.i("安装路径=="+downloadApk);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Uri apkUri = FileProvider.getUriForFile
(Objects.requireNonNull(context), BuildConfig.APPLICATION_ID +
BuildConfig.APPLICATION_ID + ".utilcode.fileProvider", file);//这句很重要
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
} else {
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Uri uri = Uri.fromFile(file);
intent.setDataAndType(uri, "application/vnd.android.package-archive");
}
context.startActivity(intent);
}
适配
private void installApp() {
Intent intent = new Intent(Intent.ACTION_VIEW);
File file = new File(FileUtils.mkdirs(DirKeys.DIR_APP_UPDATE) + "/test.apk");
Uri apkUri = FileProvider.getUriForFile(this,
BuildConfig.APPLICATION_ID + ".utilcode.fileProvider", file);//这句很重要
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
LogUtils.e("lcb", "sdk:" + Build.VERSION.SDK_INT + "走了这");
intent.setAction(Intent.ACTION_INSTALL_PACKAGE);
intent.setData(apkUri);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
intent.putExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, true);
intent.putExtra(Intent.EXTRA_ALLOW_REPLACE, true);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
} else {
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Uri uri = Uri.fromFile(file);
intent.setDataAndType(uri, "application/vnd.android.package-archive");
}
startActivity(intent);
}
android11调用相机
项目中需要使用到相机代码如下:
public static void startCarmera(Fragment fragment) {
Uri uri;
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
uri = FileProvider.getUriForFile(fragment.getActivity(),
BuildConfig.APPLICATION_ID + ".utilcode.fileProvider", getFile());
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
} else {
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(getFile()));
}
fragment.startActivityForResult(intent, RESULT_CAMERA);
}
File newFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath()
+ "/images/" + System.currentTimeMillis() + ".jpg");
if (!newFile.exists()) {
newFile.getParentFile().mkdirs();
}
mCurrentPhotoPath = newFile.getAbsolutePath();
return newFile;
}
项目中需要使用到相册代码如下:
public static void startGallery(Activity activity) {
Intent intentGallery = new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
activity.startActivityForResult(intentGallery, RESULT_GALLERY);
}
onActivityResult()中处理接收返回的图片:
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
if (requestCode == RESULT_CAMERA) {
upload(CarmeraUtil.mCurrentPhotoPath);
} else if (requestCode == RESULT_GALLERY && data != null) {
//处理来自图库的照片
Uri selectedImage = data.getData();
String[] filePathColumn = {MediaStore.Images.Media.DATA};
Cursor cursor = getContentResolver().query(selectedImage,
filePathColumn, null, null, null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
String picturePath = cursor.getString(columnIndex);
cursor.close();
upload(picturePath);
}
}
}
切记添加安装权限
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>