前言
在项目研发中,相信大家都遇到过给用户增加头像照片
的需求。
随着手机版本的不断更新,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" />
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.harry.takepicture.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>
filepaths.xml
文件:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<paths>
<external-path
name="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类型的Uri
if (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 value
index = 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;
}
}
总结
到这里就结束了。看到这里,关于上传头像的具体流程也已经清楚,最主要的代码也已经给大家粘贴了过来。
感兴趣的小伙伴们,大家赶快去测试一下吧。