针对部分高版本机型打开系统相机的适配代码
/**
* 类名称:PhotographForSignActivity
* 类功能:打开系统相机拍照
* 类作者:Qw
* 类日期:
**/
public class PhotographForSignActivity extends Activity {
private static final int PHOTO = 9; // 拍照
private String photoPath;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.empty_view);
startPhoto();
}
/**
* 打开照相机拍摄,并保存照片到指定路径中
*/
private void startPhoto() {
if (hasCamera()) {
//先验证手机是否有sdcard
String status = Environment.getExternalStorageState();
if (status.equals(Environment.MEDIA_MOUNTED)) {
try {
String photoSavePath = Environment.getExternalStorageDirectory()
+ "/相册名/";
File imgDir = new File(photoSavePath);
FileUtils.DeleteFile(photoSavePath);
if (!imgDir.exists()) {
imgDir.mkdir();
}
String photoSaveName = String.valueOf(System.currentTimeMillis())
+ ".jpg";
photoPath = photoSavePath + photoSaveName;
Intent openCameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
File MyFile = new File(photoPath);
Uri imageUri = Uri.fromFile(MyFile);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
if (!MyFile.getParentFile().exists()) MyFile.getParentFile().mkdirs();
imageUri = FileProvider.getUriForFile(this, "包名.fileprovider", MyFile);//通过FileProvider创建一个content类型的Uri
openCameraIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); //添加这一句表示对目标应用临时授权该Uri所代表的文件
openCameraIntent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);//设置Action为拍照
openCameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);//将拍取的照片保存到指定URI
startActivityForResult(openCameraIntent, PHOTO);
} else {
openCameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);//将拍取的照片保存到指定URI
startActivityForResult(openCameraIntent, PHOTO);
}
} catch (ActivityNotFoundException e) {
Toast.makeText(this, "没有找到储存目录", Toast.LENGTH_LONG).show();
}
} else {
Toast.makeText(this, "没有储存卡", Toast.LENGTH_LONG).show();
}
} else {
Toast.makeText(this, "没有可用的照相机", Toast.LENGTH_LONG).show();
finish();
}
}
/**
* 拍完照后,把照片的储存路径返回给正常签收页面处理
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == PHOTO && resultCode == Activity.RESULT_OK) {
Toast.makeText(this, "拍照完成", Toast.LENGTH_LONG).show();
EventCenter messageEvent = new EventCenter<>("photoPath", photoPath);
EventBus.getDefault().post(messageEvent);
Intent intent = new Intent();
intent.putExtra("photoPath", photoPath);
setResult(RESULT_OK, intent);
finish();
} else {
finish();
}
super.onActivityResult(requestCode, resultCode, data);
}
@Override
public void onConfigurationChanged(Configuration config) {
super.onConfigurationChanged(config);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("filePaths", photoPath);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
if (TextUtils.isEmpty(photoPath)) {
photoPath = savedInstanceState.getString("filePaths");
}
}
/**
* 判断系统中是否存在可以启动的相机应用
*
* @return 存在返回true,不存在返回false
*/
private boolean hasCamera() {
PackageManager packageManager = PhotographForSignActivity.this.getPackageManager();
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
List<ResolveInfo> list = packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
return list.size() > 0;
}
}
provider的代码放在AndroidManifest.xml application里面
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" />
</provider>
在 res/xml 目录下新建一个 xml 文件,用于存放应用需要共享的目录文件。这个 xml 文件的内容类似这样:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_files" path="."/>
</paths>
元素必须包含一到多个子元素。这些子元素用于指定共享文件的目录路径,必须是这些元素之一:
<files-path>:内部存储空间应用私有目录下的 files/ 目录,等同于 Context.getFilesDir() 所获取的目录路径;
<cache-path>:内部存储空间应用私有目录下的 cache/ 目录,等同于 Context.getCacheDir() 所获取的目录路径;
<external-path>:外部存储空间根目录,等同于 Environment.getExternalStorageDirectory() 所获取的目录路径;
<external-files-path>:外部存储空间应用私有目录下的 files/ 目录,等同于 Context.getExternalFilesDir(null) 所获取的目录路径;
<external-cache-path>:外部存储空间应用私有目录下的 cache/ 目录,等同于 Context.getExternalCacheDir();
可以看出,这五种子元素基本涵盖内外存储空间所有目录路径,包含应用私有目录。同时,每个子元素都拥有 name 和 path 两个属性。
其中,path 属性用于指定当前子元素所代表目录下需要共享的子目录名称。注意:path 属性值不能使用具体的独立文件名,只能是目录名。
而 name 属性用于给 path 属性所指定的子目录名称取一个别名。后续生成 content:// URI 时,会使用这个别名代替真实目录名。这样做的目的,很显然是为了提高安全性。
这样适配就可以解决由于7.0 及以上版本的手机用户在使用到应用部分功能时可能出现 App 崩溃闪退。其中,大部分原因都是由项目中使用到 file:// 类型的 URI 所引发的