前言
在项目研发中,相信大家都遇到过给用户增加头像照片
的需求。
随着手机版本的不断更新,android 8、android 9、android 10、android 12、android 13、鸿蒙系统等等;遇到这个功能需求,大家肯定会想,“这还不好写? 之前就已经写过了。”
把老项目跑了一遍之后发现无法运行。要不大多数就会出现奔溃的情况!
这也就遇到常见的 高版本适配情况,以及针对不同版本该如何处理?
碰到这种情况也不要慌张,博主将为大家推出两篇热乎连载篇。从两个不同开发场景下
,来给大家分享两篇文章,来更加详细的了解该如何去实现?【特此来记录】
本篇将为大家详细讲解如何调用摄像头拍照 & 选择相册,并裁剪图片。
效果
实测android 8、android 9、android 11、android 13、鸿蒙系统均有效;
手机机型分别为OPPO、华为、VIVO手机。
对于效果演示,将单独拿出两个来举例:
- VIVO android 13
- 华为 鸿蒙系统2.0.1
vivo | 华为 |
---|---|
功能
- 动态申请拍照,读,写权限
- 自定义弹出框
- 调用系统相机拍照
3.1 调用系统相机申请拍照权限回调
3.2 拍照完成回调 - 自动获取sdk权限
4.1 访问相册完成回调
具体实现
.gradle
配置文件:
AndroidManifest
文件:
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<providerandroid:name="androidx.core.content.FileProvider"android:authorities="com.harry.takepicture.provider"android:exported="false"android:grantUriPermissions="true"><meta-dataandroid:name="android.support.FILE_PROVIDER_PATHS"android:resource="@xml/filepaths" />
</provider>
filepaths.xml
文件:
<?xml version="1.0" encoding="utf-8"?>
<paths><paths><external-pathname="camera_photos"path="" /></paths><external-path name="rc_external_path" path="."/></paths>
/*** @author 拉莫帅* @date 2023/4/01* @address* @Desc TakePicture 上传头像*/
public class MainActivity extends BaseActivity implements View.OnClickListener {public static String[] permission = {Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.ACCESS_COARSE_LOCATION,Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.CAMERA};private CircleImg img;private View view;private String BaseUrl = "";private Uri newUri;private File outputImage;private Uri cropImageUri;private File fileCropUri;//裁剪的照片private Uri imageUri;//拍照所得到的图像的保存路径private static final int OUTPUT_X = 295;private static final int OUTPUT_Y = 413;private static final int CODE_GALLERY_REQUEST = 0xa0;private static final int CODE_CAMERA_REQUEST = 0xa1;private static final int CODE_RESULT_REQUEST = 0xa2;private static final int REQUESTCODE_CUTTING = 0xa3;private static final int CAMERA_PERMISSIONS_REQUEST_CODE = 0x03;private static final int STORAGE_PERMISSIONS_REQUEST_CODE = 0x04; protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setStatusBg(1);AppUtils.requestPermission(permission);img = findViewById(R.id.userinfo_iv_head);img.setOnClickListener(this);} protected View addContentLayout() {view = getLayoutInflater().inflate(R.layout.activity_main, contentLayout, false);return view;} public void onClick(View v) {switch (v.getId()) {case R.id.userinfo_iv_head:select();break;case R.id.rl_head_camera:takePhoto();AppUtils.dismiss();break;case R.id.rl_head_photo:autoObtainStoragePermission();AppUtils.dismiss();break;case R.id.rl_head_cancel:AppUtils.dismiss();break;}}private void select() { AppUtils.selectPhoto(MainActivity.this, R.layout.dialog_head, R.layout.activity_main, this);}/*** 拍照** @param*/private void takePhoto() {if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED|| ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) {ToastUtils.showShort(this, "您已经拒绝过一次");}ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE}, CAMERA_PERMISSIONS_REQUEST_CODE);} else {//有权限直接调用系统相机拍照if (AppUtils.hasSdcard()) {outputImage = new File(Environment.getExternalStorageDirectory().getPath(), System.currentTimeMillis() + ".jpg");//通过FileProvider创建一个content类型的Uriif (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {imageUri = FileProvider.getUriForFile(this, "com.harry.takepicture.provider", outputImage);} else {imageUri = Uri.fromFile(outputImage);}PhotoUtils.takePicture(this, imageUri, CODE_CAMERA_REQUEST); } else {ToastUtils.showShort(this, "设备没有SD卡!");}}} public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {super.onRequestPermissionsResult(requestCode, permissions, grantResults);switch (requestCode) {//调用系统相机申请拍照权限回调case CAMERA_PERMISSIONS_REQUEST_CODE: {if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {if (AppUtils.hasSdcard()) {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {imageUri = FileProvider.getUriForFile(MainActivity.this, "com.harry.takepicture.provider", outputImage);} else {imageUri = Uri.fromFile(outputImage);}PhotoUtils.takePicture(this, imageUri, CODE_CAMERA_REQUEST); } else {ToastUtils.showShort(this, "设备没有SD卡!");}} else {ToastUtils.showShort(this, "请允许打开相机!!");}break;}}}/*** 自动获取sdk权限*/private void autoObtainStoragePermission() {if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, STORAGE_PERMISSIONS_REQUEST_CODE);} else {PhotoUtils.openPic(this, CODE_GALLERY_REQUEST);}} protected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);if (resultCode == RESULT_OK) {fileCropUri = new File(Environment.getExternalStorageDirectory(), System.currentTimeMillis() + ".jpg");switch (requestCode) {//拍照完成回调case CODE_CAMERA_REQUEST:if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {Uri contentUri = FileProvider.getUriForFile(this, "com.harry.takepicture.provider", outputImage);cropPhoto(contentUri);} else {imageUri = Uri.fromFile(outputImage);cropPhoto(imageUri);}//访问相册完成回调case CODE_GALLERY_REQUEST:if (AppUtils.hasSdcard()) {cropImageUri = Uri.fromFile(fileCropUri);if (data == null) {return;} else {newUri = getUri(data);}PhotoUtils.cropImageUri(this, newUri, cropImageUri, 1, 1, OUTPUT_X, OUTPUT_Y, CODE_RESULT_REQUEST);} else {ToastUtils.showShort(this, "设备没有SD卡!");}break;case REQUESTCODE_CUTTING:if (data != null) {setPicToView(data);}break;case CODE_RESULT_REQUEST:String a = cropImageUri.getPath();Log.e("tb", "a---" + a);Bitmap bitmap = PhotoUtils.getBitmapFromUri(cropImageUri, this);if (bitmap != null) {File file = new File(a);Log.e("tb", "file--------------------------" + file);BaseUrl = Base64Utils.getImageStr(file);Log.e("tb", "BaseUrl--------------------------" + BaseUrl);showImages(bitmap, a);}break;default:}}}private void setPicToView(Intent picdata) {Bundle extras = picdata.getExtras();if (extras != null) {// 取得SDCard图片路径做显示Bitmap photo = extras.getParcelable("data");String saveFile = FileUtil.saveFile(this, "crop", photo);if (photo != null) {File file = new File(saveFile);Log.e("tb", "file--------------------------" + file);BaseUrl = Base64Utils.getImageStr(file);Log.e("tb", "BaseUrl--------------------------" + BaseUrl);showImages(photo, saveFile);}}}/*** 裁剪* * @param uri*/private void cropPhoto(Uri uri) {Intent intent = new Intent("com.android.camera.action.CROP");intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);intent.setDataAndType(uri, "image/*");intent.putExtra("crop", "true");intent.putExtra("aspectX", 1);intent.putExtra("aspectY", 1);intent.putExtra("outputX", 300);intent.putExtra("outputY", 300);intent.putExtra("return-data", true);Log.e("tag", "intent====" + intent);startActivityForResult(intent, REQUESTCODE_CUTTING);}/*** 展示* * @param bitmap* @param urlpath*/private void showImages(Bitmap bitmap, String urlpath) {Drawable drawable = new BitmapDrawable(null, bitmap);Log.e("tag", "urlPath====" + urlpath);img.setImageDrawable(drawable);}/*** 解决手机上获取图片路径为null的情况** @param intent* @return*/public Uri getUri(android.content.Intent intent) {Uri uri = intent.getData();String type = intent.getType();if (uri.getScheme().equals("file") && (type.contains("image/"))) {String path = uri.getEncodedPath();if (path != null) {path = Uri.decode(path);ContentResolver cr = this.getContentResolver();StringBuffer buff = new StringBuffer();buff.append("(").append(MediaStore.Images.ImageColumns.DATA).append("=").append("'" + path + "'").append(")");Cursor cur = cr.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,new String[]{MediaStore.Images.ImageColumns._ID},buff.toString(), null, null);int index = 0;for (cur.moveToFirst(); !cur.isAfterLast(); cur.moveToNext()) {index = cur.getColumnIndex(MediaStore.Images.ImageColumns._ID);// set _id valueindex = cur.getInt(index);}if (index == 0) {// do nothing} else {Uri uri_temp = Uri.parse("content://media/external/images/media/"+ index);if (uri_temp != null) {uri = uri_temp;}}}}return uri;}
}
总结
到这里就结束了。看到这里,关于上传头像的具体流程也已经清楚,最主要的代码也已经给大家粘贴了过来。
完整版源码下载地址:Android + <调用相机拍照 & 选择相册> + 数码相机
感兴趣的小伙伴们,大家赶快去测试一下吧。