Android 7-11图片裁剪与分享适配

分享

URI转换工具

class ImageUtils {
    companion object {

        fun getImageContentUri(context: Context, imageFile: File): Uri? {
            val filePath = imageFile.absolutePath
            val cursor = context.contentResolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                    arrayOf(MediaStore.Images.Media._ID), MediaStore.Images.Media.DATA + "=? ",
                    arrayOf(filePath), null)
            if (cursor != null && cursor.moveToFirst()) {
                val id = cursor.getInt(cursor.getColumnIndex(MediaStore.MediaColumns._ID))
                val baseUri = Uri.parse("content://media/external/images/media")
                return Uri.withAppendedPath(baseUri, "" + id)
            } else {
                if (imageFile.exists()) {
                    val values = ContentValues()
                    values.put(MediaStore.Images.Media.DATA, filePath)
                    return context.contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)
                } else {
                    return null
                }
            }
        }

        fun getUriForFile(context: Context, file: File): Uri {
            if (context == null || file == null) {
                throw  NullPointerException();
            }
            var uri: Uri;
            if (Build.VERSION.SDK_INT >= 24) {
                uri = FileProvider.getUriForFile(context.applicationContext,
                        BuildConfig.APPLICATION_ID + ".fileProvider", file);
            } else {
                uri = Uri.fromFile(file);
            }
            return uri;
        }


        @TargetApi(19)
        @JvmStatic
        fun getPathFromUri(context: Context, uri: Uri): String? {
            val isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT

            // DocumentProvider
            if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
                // ExternalStorageProvider
                if (isExternalStorageDocument(uri)) {
                    val docId = DocumentsContract.getDocumentId(uri)
                    val split = docId.split(":").toTypedArray()
                    val type = split[0]
                    if ("primary".equals(type, ignoreCase = true)) {
                        return Environment.getExternalStorageDirectory().toString() + "/" + split[1]
                    }
                } else if (isDownloadsDocument(uri)) {
                    val id = DocumentsContract.getDocumentId(uri)
                    val contentUri = ContentUris.withAppendedId(
                            Uri.parse("content://downloads/public_downloads"), java.lang.Long.valueOf(id))
                    return getDataColumn(context, contentUri, null, null)
                } else if (isMediaDocument(uri)) {
                    val docId = DocumentsContract.getDocumentId(uri)
                    val split = docId.split(":").toTypedArray()
                    val type = split[0]
                    var contentUri: Uri? = null
                    if ("image" == type) {
                        contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
                    } else if ("video" == type) {
                        contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
                    } else if ("audio" == type) {
                        contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
                    }
                    val selection = "_id=?"
                    val selectionArgs = arrayOf(
                            split[1]
                    )
                    return getDataColumn(context, contentUri, selection, selectionArgs)
                }
            } else if ("content".equals(uri.scheme, ignoreCase = true)) {
                // Return the remote address
                return if (isGooglePhotosUri(uri)) {
                    uri.lastPathSegment
                } else getDataColumn(context, uri, null, null)
            } else if ("file".equals(uri.scheme, ignoreCase = true)) {
                return uri.path
            }
            return ""
        }

        /**
         * @param uri The Uri to check.
         * @return Whether the Uri authority is ExternalStorageProvider.
         */
        @JvmStatic
        fun isExternalStorageDocument(uri: Uri): Boolean {
            return "com.android.externalstorage.documents" == uri.authority
        }

        /**
         * @param uri The Uri to check.
         * @return Whether the Uri authority is DownloadsProvider.
         */
        @JvmStatic
        fun isDownloadsDocument(uri: Uri): Boolean {
            return "com.android.providers.downloads.documents" == uri.authority
        }

        /**
         * @param uri The Uri to check.
         * @return Whether the Uri authority is MediaProvider.
         */
        @JvmStatic
        fun isMediaDocument(uri: Uri): Boolean {
            return "com.android.providers.media.documents" == uri.authority
        }

        /**
         * @param uri The Uri to check.
         * @return Whether the Uri authority is Google Photos.
         */
        @JvmStatic
        fun isGooglePhotosUri(uri: Uri): Boolean {
            return "com.google.android.apps.photos.content" == uri.authority
        }

        @JvmStatic
        fun getDataColumn(context: Context, uri: Uri?, selection: String?, selectionArgs: Array<String>?): String? {
            var cursor: Cursor? = null
            val column = MediaStore.Images.Media.DATA
            val projection = arrayOf(column)
            try {
                cursor = context.contentResolver.query(uri!!, projection, selection, selectionArgs, null)
                if (cursor != null && cursor.moveToFirst()) {
                    val index = cursor.getColumnIndexOrThrow(column)
                    return cursor.getString(index)
                }
            } finally {
                cursor?.close()
            }
            return null
        }
    }

}

单图分享

 Uri uri = ImageUtils.Companion.getUriForFile(mContext, ifrFile);
 Intent sharedIntent = new Intent();
 sharedIntent.setAction(Intent.ACTION_SEND);
 sharedIntent.putExtra(Intent.EXTRA_STREAM, uri);
 sharedIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
 sharedIntent.setType("image/*");
 startActivity(Intent.createChooser(sharedIntent, mContext.getString(R.string.share_to)));

单视频分享

Uri uri = ImageUtils.Companion.getUriForFile(mContext, ifrFile);
Intent sharedIntent = new Intent();
sharedIntent.setAction(Intent.ACTION_SEND);
sharedIntent.putExtra(Intent.EXTRA_STREAM, uri);
sharedIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
sharedIntent.setType("video/*");
startActivity(Intent.createChooser(sharedIntent, mContext.getString(R.string.share_to)));

多文件分享

//fori···
	Uri uri;
	if (Build.VERSION.SDK_INT >= 30) {
	    uri = ImageUtils.Companion.getUriForFile(mContext, ifrFile);
	} else {
	    uri = ImageUtils.Companion.getImageContentUri(mContext, ifrFile);
	}
	uriList.add(uri);

//分享
Intent sharedIntent = new Intent();
sharedIntent.setAction(Intent.ACTION_SEND_MULTIPLE);
sharedIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
sharedIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uriList);
if (type == Constants.MEDIA_TYPE_IMAGE) {
sharedIntent.setType("image/*");
} else {
sharedIntent.setType("video/*");
}
startActivity(Intent.createChooser(sharedIntent, mContext.getString(R.string.share_to)));

图片裁剪

图片存储路径

     /**
         * 获取内置SD卡路径
         *
         * @return
         */
        fun getInnerSDCardPath(Context context): String {
            //target sdk 设置为30且 、Android11设备上运行
            var path:String? = null
            if(Build.VERSION.SDK_INT >= 29){
                path = context.getExternalFilesDir(Environment.DIRECTORY_DCIM)!!.absolutePath
            }else{
                path =  Environment.getExternalStorageDirectory().absolutePath
            } 
            return path
        }

图片选择

    const val BASE = "XXXX"
    const val IMAGE_TAKEPHOTE_PATH = "TakePhote"
    const val IMAGE_TAKEPHOTECROP_PATH = "TakePhoteCROP"

	//图库
    private void openGallery() {
        Intent intent = new Intent(Intent.ACTION_PICK);
        intent.setType("image/jpeg");
        startActivityForResult(intent, SCAN_OPEN_PHONE);
    }

    // 拍照
    private void takePhoto() {
        // 要保存的文件名
        String time = new SimpleDateFormat("yyyyMMddHHmmss", Locale.CHINA).format(new Date());
        fileName = "photo_" + time;
        // 创建一个文件夹
        File mCutFile = new File(SDCardUtils.Companion.getInnerSDCardPath() + File.separator + Constants.BASE
                + File.separator + Constants.IMAGE_TAKEPHOTE_PATH, fileName + ".jpeg");
        if (!mCutFile.getParentFile().exists()) {
            mCutFile.getParentFile().mkdirs();
        }
        // 要保存的图片文件
        imgFile = mCutFile;
        // 将file转换成uri
        if (Build.VERSION.SDK_INT >= 30) {
            // 通过 MediaStore API 插入file 为了拿到系统裁剪要保存到的uri(因为App没有权限不能访问公共存储空间,需要通过 MediaStore API来操作)
            ContentValues values = new ContentValues();
            values.put(MediaStore.Images.Media.DATA, imgFile.getAbsolutePath());
            values.put(MediaStore.Images.Media.DISPLAY_NAME, fileName);
            values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
            imgUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
            Log.w(TAG, "photoUri:" + imgUri.getAuthority() + ",photoUri:" + imgUri.getPath());
        } else {
            imgUri = Uri.fromFile(imgFile);
        }

        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        // 添加Uri读取权限
        intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
        // 或者
//        grantUriPermission("com.rain.takephotodemo", imgUri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
        // 添加图片保存位置

        intent.putExtra(MediaStore.EXTRA_OUTPUT, imgUri);
        intent.putExtra("return-data", false);
        startActivityForResult(intent, REQUEST_TAKE_PHOTO);
    }

ucrop裁剪

implementation 'com.github.yalantis:ucrop:2.2.3'

  String time = new SimpleDateFormat("yyyyMMddHHmmss", Locale.CHINA).format(new Date());
        // 指定裁剪完成以后的图片所保存的位置,pic info显示有延时
        fileName = "photo_" + time;
        File mCutFile = new File(SDCardUtils.Companion.getInnerSDCardPath() + File.separator + Constants.BASE
                + File.separator + Constants.IMAGE_TAKEPHOTECROP_PATH, fileName + ".jpeg");
        if (!mCutFile.getParentFile().exists()) {
            mCutFile.getParentFile().mkdirs();
        }
        uploadFile = mCutFile;
        mCutUri = Uri.fromFile(mCutFile);
        uploadName = fileName + ".jpeg";

        UCrop.Options options = new UCrop.Options();
        //设置位图最大大小
        options.withMaxResultSize(200, 200);
        //宽高比
        options.withAspectRatio(1, 1);
        options.setToolbarColor(ContextCompat.getColor(this, R.color.black));
        options.setToolbarTitle(uploadName);
        options.setStatusBarColor(ContextCompat.getColor(this, R.color.black));
        //设置Toolbar控件颜色
        options.setToolbarWidgetColor(ContextCompat.getColor(this, R.color.white));
        //设置Toolbar返回按钮图片
//        options.setToolbarCancelDrawable(R.drawable.);
        //设置Toolbar确定按钮图片
//        options.setToolbarCropDrawable(R.drawable.);
        options.setFreeStyleCropEnabled(true);
        //jpeg 模式
        options.setCompressionFormat(Bitmap.CompressFormat.JPEG);
        /*底部控制栏颜色*/
        options.setRootViewBackgroundColor(ContextCompat.getColor(this, R.color.black));
        UCrop.of(sourceUri, mCutUri).withOptions(options).start(this);

系统裁剪

String time = new SimpleDateFormat("yyyyMMddHHmmss", Locale.CHINA).format(new Date());

        Intent intent = new Intent("com.android.camera.action.CROP"); //打开系统自带的裁剪图片的intent
        intent.setDataAndType(uri, "image/*");
        intent.putExtra("crop", "true");

        // 注意一定要添加该项权限,否则会提示无法裁剪
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);

        intent.putExtra("scale", true);

        // 设置裁剪区域的宽高比例
        intent.putExtra("aspectX", 1);
        intent.putExtra("aspectY", 1);

        // 设置裁剪区域的宽度和高度
        intent.putExtra("outputX", 200);
        intent.putExtra("outputY", 200);

        // 取消人脸识别
        intent.putExtra("noFaceDetection", false);
        // 图片输出格式
        intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
        // 若为false则表示不返回数据
        intent.putExtra("return-data", false);

        // 指定裁剪完成以后的图片所保存的位置,pic info显示有延时
        fileName = "photo_" + time;
        File mCutFile = new File(SDCardUtils.Companion.getInnerSDCardPath() + File.separator + Constants.BASE
                + File.separator + Constants.IMAGE_TAKEPHOTECROP_PATH, fileName + ".jpeg");
        if (!mCutFile.getParentFile().exists()) {
            mCutFile.getParentFile().mkdirs();
        }
        uploadFile = mCutFile;
        mCutUri = Uri.fromFile(mCutFile);
        uploadName = fileName + ".jpeg";
 

        intent.putExtra(MediaStore.EXTRA_OUTPUT, mCutUri);
        Toast.makeText(this, R.string.corp_pic, Toast.LENGTH_SHORT).show();
        // 以广播方式刷新系统相册,以便能够在相册中找到刚刚所拍摄和裁剪的照片
        Intent intentBc = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
        intentBc.setData(uri);
        this.sendBroadcast(intentBc);

        startActivityForResult(intent, REQUEST_CROP); //设置裁剪参数显示图片至ImageVie

Android 7

 <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="包名.fileProvider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>

file_paths

'name' 随便取,自己定义路径,'.'代表根目录

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <!--SD卡-->
    <external-path name="xx_images" path="."/>

    <external-path name="xx_videos" path="."/>

    <external-path name="images" path="."/>


    <!--Android 11 不支持 SD卡的任何读写 只能在Data/包名下读写 -->
    <external-files-path name="n_xx_images" path="." />

    <external-files-path name="n_xx_videos" path="." />

    <external-files-path name="n_images" path="."/>

</paths>

说明

该配置也仅仅适合Android7,到了Android 11不适用

<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();
 

Android 10

android:requestLegacyExternalStorage="true"

参考链接:
《Android CameraX适配Android11的踩坑之路。》1


  1. Android CameraX适配Android11的踩坑之路。 ↩︎

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值