试着加个动态申请权限试试
背景:
在安卓7.0手机上,调用系统相机拍照,结果出现闪退。
原因:
Android7.0中为了提高私有文件的安全性,禁止向你的应用外公开 file:// URI。 如果一项包含文件 file:// URI类型 的 Intent 离开你的应用,应用失败,并出现 FileUriExposedException 异常。
解决方案:
FileProvider是Android 7.0出现的新特性,它是ContentProvider的子类,可以通过创建一个Content URI并赋予临时的文件访问权限来代替File URI实现文件共享。
AndroidMainfest.xml为:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.androidcamera"> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <application 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/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> <intent-filter> <action android:name="android.media.action.IMAGE_CAPTURE" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity> <!-- android:name="android.support.v4.content.FileProvider" --> <provider android:authorities="com.example.androidcamera.fileprovider" android:name="androidx.core.content.FileProvider" android:grantUriPermissions="true" android:exported="false"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/filepaths"/> </provider> </application> </manifest>
在res--->增加xml文件夹---->增加filepaths.xml文件
<?xml version="1.0" encoding="utf-8"?> <resources> <paths> <external-path name="external_path" path="." /> </paths> </resources>
修改MainActivity.java文件为
package com.example.androidcamera; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; import androidx.core.content.FileProvider; import android.content.ActivityNotFoundException; import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.provider.MediaStore; import android.view.View; import android.widget.ImageView; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; public class MainActivity extends AppCompatActivity { private static int REQ_1 = 1; private static int REQ_2 = 2; private ImageView mImageView; private String mFilePath; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mImageView = (ImageView) findViewById(R.id.iv); mFilePath = Environment.getExternalStorageDirectory().getPath(); mFilePath = mFilePath + "/" + "temp.png"; } public void startCamera1(View view){ Intent intent= new Intent(MediaStore.ACTION_IMAGE_CAPTURE); startActivityForResult(intent, REQ_1); } public void startCamera2(View view){ Intent intent= new Intent(MediaStore.ACTION_IMAGE_CAPTURE); // Uri photoUri = Uri.fromFile(new File(mFilePath)); Uri photoUri = getUriForFile(MainActivity.this,new File(mFilePath)); intent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri); startActivityForResult(intent, REQ_2); } private static Uri getUriForFile(Context context, File file) { if (context == null || file == null) { throw new NullPointerException(); } Uri uri; //判断是否是AndroidN以及更高的版本 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { //如果SDK版本>=24,即:Build.VERSION.SDK_INT >= 24 // uri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".fileProvider", file); uri = FileProvider.getUriForFile(context, "com.example.androidcamera.fileprovider", file); } else { uri = Uri.fromFile(file); } return uri; } private Intent getInstallIntent() { String savePath = "null"; String appName = "AndroidCamera"; String fileName = savePath + appName + ".apk"; Uri uri = null; Intent intent = new Intent(Intent.ACTION_VIEW); try { if (Build.VERSION.SDK_INT >= 24) {//7.0 Android N //com.xxx.xxx.fileprovider为上述manifest中provider所配置相同 Context mContext = null; uri = FileProvider.getUriForFile(mContext, "com.example.androidcamera.fileprovider", new File(fileName)); intent.setAction(Intent.ACTION_INSTALL_PACKAGE); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);//7.0以后,系统要求授予临时uri读取权限,安装完毕以后,系统会自动收回权限,该过程没有用户交互 } else {//7.0以下 uri = Uri.fromFile(new File(fileName)); intent.setAction(Intent.ACTION_VIEW); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); } intent.setDataAndType(uri, "application/vnd.android.package-archive"); startActivity(intent); return intent; } catch (IllegalArgumentException e) { e.printStackTrace(); e.printStackTrace(); }catch (Exception e){ } return intent; } @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK) { if (requestCode == REQ_1) { Bundle bundle = data.getExtras(); Bitmap bitmap = (Bitmap) bundle.get("data"); mImageView.setImageBitmap(bitmap); } else if (requestCode == REQ_2) { FileInputStream fis = null; try { fis =new FileInputStream(mFilePath); Bitmap bitmap = BitmapFactory.decodeStream(fis); mImageView.setImageBitmap(bitmap); } catch (FileNotFoundException e) { e.printStackTrace(); } finally { try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } } } } }
这们startCamera2就能在真手机上打开拍照了。
求回答加一,我也有这种问题
请问怎么解决的?
...闪退没大佬来解决一下吗
动态权限怎么添加啊,我这边拍了照图片不显示,程序也没崩溃,debug显示文件错误
如果已经升级到android6.0以上会有个运行时权限,按老师这样敲就sd卡中有图片但是加载不出来。
解决方法:
1、由于拍照要用到CAMERA权限,所以现在Manifest文件中加上
<uses-permission android:name="android.permission.CAMERA"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
2、申请运行时权限
将第二个按钮的click事件修改如下
btnStartCamera2.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { List<String> permissionList = new ArrayList<String>(); if(ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { permissionList.add(Manifest.permission.READ_EXTERNAL_STORAGE); } if(ContextCompat.checkSelfPermission(MainActivity.this,Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { permissionList.add(Manifest.permission.WRITE_EXTERNAL_STORAGE); } if(ContextCompat.checkSelfPermission(MainActivity.this,Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { permissionList.add(Manifest.permission.CAMERA); } if(!permissionList.isEmpty()) { String[] permissions = permissionList.toArray(new String[permissionList.size()]); ActivityCompat.requestPermissions(MainActivity.this,permissions,1); } else { Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); Uri photoUri = Uri.fromFile(new File(mFilePath)); intent.putExtra(MediaStore.EXTRA_OUTPUT,photoUri); startActivityForResult(intent,REQUEST2); } } });
主要进行运行时权限的申请工作,申请了ManiFest中申请的三个静态权限。
然后
在MainActivity中添加如下代码
@Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if(requestCode == 1) { if(grantResults.length > 0) { for(int result : grantResults) { if(result != PackageManager.PERMISSION_GRANTED) { Toast.makeText(MainActivity.this,"必须同意所有权限才能使用本程序",Toast.LENGTH_SHORT).show(); finish(); return; } } Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); Uri photoUri = Uri.fromFile(new File(mFilePath)); intent.putExtra(MediaStore.EXTRA_OUTPUT,photoUri); startActivityForResult(intent,REQUEST2); } else { Toast.makeText(MainActivity.this,"发生未知错误",Toast.LENGTH_SHORT).show(); finish(); } } }
主要进行申请权限时是否被同意的情况
最后
如果三个权限都同意了的话ImageView就能成功加载出图片了。
祝你成功了。
Environment.getExternalStorageDirectory().getPath()
改成
Environment.getRootDirectory().getPath()
intent.putExtra第二参数是uri,不是传递file!
无语,你得有多粗心啊。。。
我和你一样,我是uri解析的是否没有从文件中解析
错误:
Uri photoUri=Uri.parse(mFilePath);
正确:
Uri photoUri=Uri.fromFile(new File(mFilePath));
异常信息贴出来看看
好想法哦。
有id吗
可以手动写到系统保存路径,比如我的手机内存路径根目录是/storage/emulated/0,就可以写成/storage/emulated/0/aaa.png
源码:http://blog.csdn.net/chenzheng8975/article/details/53943775
有可能是安卓6.0的权限问题,http://stackoverflow.com/questions/23527767/open-failed-eacces-permission-denied
我的是因为没有打开手机权限,进手机设置把自己写的APP的权限全打开
我猜 是你的图片太大了。 是不是拍完的图片有2兆 3兆以上。如果是 那就在转换为bitmap的时候配置下。
1. 插入一张外置SD卡后
内置SD卡路径:/storage/emulated/0
外置SD卡路径:/storage/extSdCard
2. 取出外置SD卡后
内置SD卡路径:/storage/emulated/0
String path = null;
try {
path = android.os.SystemProperties.get("external_sd_path");
LogUtils.d(TAG, "current card id= " + path);
} catch (IllegalArgumentException e) {
}
if(path.equals("/storage/sdcard0")){
LogUtils.d(TAG, "current card id= 有sd卡" + path);
}else{
LogUtils.d(TAG, "current card id= 没有sd卡" + path);
}
通过以上代码判断手机没有外置存储卡的话就把文件的存储路径改成内置存储路径即可,当然,最好用Environment.getExternalStorageDirectory() 这样获取内置存储的路径地址.
压缩下就行
是的,data是bundle中封装一个数据的字段,直接获取该属性就可以得到图片的数据
哈哈哈哈