registerForActivityResult solicitar permiso/fotografía/seleccionar imagen de video/recortar imagen

Permiso relacionado

//近似定位(模糊定位)
Manifest.permission.ACCESS_COARSE_LOCATION
//精确定位
Manifest.permission.ACCESS_FINE_LOCATION

Determinar si el servicio de ubicación está habilitado

// 判断定位服务是否开启
    private fun checkLocationServiceEnable(): Boolean {
        val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
        val gps = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)
        val network = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)
        return gps || network
    }

Comprueba si tienes un determinado permiso

//检查权限
    private fun checkPermission(): Boolean {
        return PackageManager.PERMISSION_GRANTED == if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            PermissionChecker.checkSelfPermission(App.instance, Manifest.permission.WRITE_EXTERNAL_STORAGE)
        } else {
            ContextCompat.checkSelfPermission(App.instance, Manifest.permission.WRITE_EXTERNAL_STORAGE)
        }
    }

Almacenamiento de particiones

/**
     * 将私有目录文件拷贝到公共目录,仅针对Android10及以上版本
     * @param sourceFile 私有目录的源文件
     * */
    @RequiresApi(Build.VERSION_CODES.Q)
    private fun copyFileToPublicDir(sourceFile: File) {

        val contentValues = ContentValues().apply {
            put(MediaStore.Video.Media.DISPLAY_NAME, sourceFile.name)
            put(MediaStore.Video.Media.RELATIVE_PATH, Environment.DIRECTORY_MOVIES)
            put(MediaStore.Video.Media.IS_PENDING, true)
            put(MediaStore.Video.Media.MIME_TYPE, "video/mp4")
            put(MediaStore.Video.Media.DATE_TAKEN, System.currentTimeMillis())
        }

        contentResolver.insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, contentValues)?.apply {
            writeFile(contentValues, this, sourceFile)
        }
    }

    @RequiresApi(Build.VERSION_CODES.Q)
    private fun writeFile(contentValues: ContentValues, uri: Uri, sourceFile: File) {

        lifecycleScope.launch(Dispatchers.IO) {
            try {
                val optStream = contentResolver.openOutputStream(uri)
                val fileInputStream = sourceFile.inputStream()
                val byteArray = ByteArray(1024)
                fileInputStream.use { input ->
                    optStream?.use {
                        while (true) {
                            val readLeg = input.read(byteArray)
                            if (readLeg == -1) break
                            optStream.write(byteArray, 0, readLeg)
                        }
                    }
                }
                // 更新系统库文件
                contentValues.clear()
                contentValues.put(MediaStore.Video.Media.IS_PENDING, false)
                val num = contentResolver.update(uri, contentValues, null, null)
                if (num > 0) {
                    // 更新成功
                }
            } catch (ex: Exception) {
                Log.e(tag, ex.message ?: "copyFileToPublicDir error")
            }
        }
    }

Formulario de solicitud, paquete multiautoridad

import androidx.activity.result.ActivityResultCallback
import androidx.activity.result.ActivityResultCaller
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts

/**
 * 使用registerForActivityResult请求权限封装
 * @param caller 调用者,一般为Activity
 * */
class PermissionLauncher(caller: ActivityResultCaller) {

    // 请求权限,支持单、多权限申请
    private var launcher: ActivityResultLauncher<Array<String>>

    // 权限申请结果回调
    private lateinit var callback: ActivityResultCallback<Boolean>

    // 是否多权限
    private var multiPermission = false

    init {
        launcher = caller.registerForActivityResult(
            ActivityResultContracts.RequestMultiplePermissions()
        ) {
            // 多权限返回是否全部通过结果
            callback.onActivityResult(
                if (multiPermission) it.values.contains(false).not()
                else it.values.first()
            )
        }
    }

    /**
     * 启动请求权限
     * @param permissions 权限列表
     * @param callback 权限申请结果回调
     * */
    fun launch(
        permissions: Array<String>,
        callback: ActivityResultCallback<Boolean>
    ) {
        this.callback = callback
        // 是否多权限,回调区分处理
        multiPermission = permissions.size > 1
        launcher.launch(permissions)
    }
}

Ejemplo de uso:

// 权限请求,在Activity中
    private val permissionRequest = PermissionLauncher(this)
    
    private fun requestPermission() {
        permissionRequest.launch(
            arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE
        )){ granted -> 
            if (granted) "permission ok".showToast()
            else "permission defined".showToast()
        }
    }

1. Solicitar permiso de entrada

//注册权限请求
private final ActivityResultLauncher<String> mActLauncherPermission = registerForActivityResult(
            new ActivityResultContracts.RequestPermission(), result -> Log.i("zhao", "权限:" + result)
    );

//在需要的时候启动权限请求
private void requestPermission() {

        mActLauncherPermission.launch(Manifest.permission.CAMERA);
    }

2. Solicita múltiples permisos

//多权限请求
    protected final ActivityResultLauncher<String[]> mResultLauncherPermission =
            registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), result -> {
                boolean allOk = true;
                for (String item : result.keySet()) {
                    try {
                        boolean bOK = result.get(item);
                        if (!bOK) {
                            allOk = false;
                            break;
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                Log.i("zhao", "所有权限:" + allOk);
            });


//请求多种类权限
    private void requestMultiPermissions(String[] permissions) {
        mResultLauncherPermission.launch(permissions);
    }

3. Toma fotografías

Imagen de retorno Formato de mapa de bits

//拍照
private final ActivityResultLauncher<Void> mLauncherCamera = registerForActivityResult(
            new ActivityResultContracts.TakePicturePreview(), result -> {
                //result为拍摄照片Bitmap格式
            });

//启动拍照(注意先检查权限)
//开启拍照,返回结果Bitmap
    private void launchCamera() {
        mLauncherCamera.launch(null);
    }

Tome una foto y devuelva el formato Uri

(1) Personalizar primero ActivityResultContract

import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.MediaStore;

import androidx.activity.result.contract.ActivityResultContract;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.FileProvider;

import java.io.File;

/**
 * 拍照返回存储的图片的uri
 */
public class TakeCameraUri extends ActivityResultContract<Object, Uri> {

    //拍照返回的uri
    private Uri uri;

    @NonNull
    @Override
    public Intent createIntent(@NonNull Context context, Object input) {

        String mimeType = "image/jpeg";
        String fileName = System.currentTimeMillis() + ".jpg";
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {

            ContentValues values = new ContentValues();
            values.put(MediaStore.MediaColumns.DISPLAY_NAME, fileName);
            values.put(MediaStore.MediaColumns.MIME_TYPE, mimeType);
            values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM);
            uri = context.getContentResolver()
                    .insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
        } else {
            //应用认证表示
            String authorities = "这里为您自己定义的fileProvider";
            uri = FileProvider.getUriForFile(context, authorities,
                    new File(context.getExternalCacheDir().getAbsolutePath(), fileName));
        }
        return new Intent(MediaStore.ACTION_IMAGE_CAPTURE).putExtra(MediaStore.EXTRA_OUTPUT, uri);
    }

    @Override
    public Uri parseResult(int resultCode, @Nullable Intent intent) {
        return uri;
    }
}

(2) Registrar llamada

//注册调用
private final ActivityResultLauncher<Object> mLauncherCameraUri = registerForActivityResult(
            new TakeCameraUri(), new ActivityResultCallback<Uri>() {
                @Override
                public void onActivityResult(Uri result) {
                    //这里返回图片的Uri
                }
            }
    );

//调用拍照
private void launchCameraUri() {
        mLauncherCameraUri.launch(null);
    }

4. Seleccione una imagen

//选取图片
private final ActivityResultLauncher<String> mLauncherAlbum = registerForActivityResult(
            new ActivityResultContracts.GetContent(), result -> {
                //result为选取的图片的Uri
            }
    );

//调用相册选择图片
    protected void launchAlbum() {
        mLauncherAlbum.launch("image/*");
    }

5. Seleccionar vídeo

private final ActivityResultLauncher<String> mActLauncherAlbum = registerForActivityResult(
            new ActivityResultContracts.GetContent(), result -> {
                //视频文件路径
                String videoPath = result.getPath();
            }
    );


//选取视频文件(和选取相册类似)
    private void launchVideoPick() {
        mActLauncherAlbum.launch("video/*");
    }

6. Recorta la imagen

(1) Clase de configuración de parámetros de cultivo CropImageResult

import android.net.Uri;

/**
 * 裁剪图片配置类
 */
public class CropImageResult {

    private Uri uri;
    //裁剪框横向比例数值
    private int aspectX;
    //裁剪框纵向比例数值
    private int aspectY;

    public CropImageResult(Uri uri, int aspectX, int aspectY) {
        this.uri = uri;
        this.aspectX = aspectX;
        this.aspectY = aspectY;
    }

    public Uri getUri() {
        return uri;
    }

    public void setUri(Uri uri) {
        this.uri = uri;
    }

    public int getAspectX() {
        return aspectX;
    }

    public void setAspectX(int aspectX) {
        this.aspectX = aspectX;
    }

    public int getAspectY() {
        return aspectY;
    }

    public void setAspectY(int aspectY) {
        this.aspectY = aspectY;
    }
}

(2) Clase de configuración de salida de cultivo CropImage

import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.MediaStore;
import android.webkit.MimeTypeMap;

import androidx.activity.result.contract.ActivityResultContract;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import java.io.File;

/**
 * 裁剪图片
 */
public class CropImage extends ActivityResultContract<CropImageResult, Uri> {

    //裁剪后输出的图片文件Uri
    private Uri mUriOutput;

    @NonNull
    @Override
    public Intent createIntent(@NonNull Context context, CropImageResult input) {

        //把CropImageResult转换成裁剪图片的意图
        Intent intent = new Intent("com.android.camera.action.CROP");
        String mimeType = context.getContentResolver().getType(input.getUri());
        String imageName = System.currentTimeMillis() +
                MimeTypeMap.getSingleton().getExtensionFromMimeType(mimeType) + "";
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            ContentValues values = new ContentValues();
            values.put(MediaStore.MediaColumns.DISPLAY_NAME, imageName);
            values.put(MediaStore.MediaColumns.MIME_TYPE, mimeType);
            values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM);
            mUriOutput = context.getContentResolver()
                    .insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
        } else {
            mUriOutput = Uri.fromFile(new File(context.getExternalCacheDir().getAbsolutePath(), imageName));
        }
        context.grantUriPermission(context.getPackageName(), mUriOutput, Intent.FLAG_GRANT_READ_URI_PERMISSION);
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        //去除默认的人脸识别,否则和剪裁匡重叠
        intent.putExtra("noFaceDetection", true);
        intent.setDataAndType(input.getUri(), mimeType);
        //crop=true 有这句才能出来最后的裁剪页面.
        intent.putExtra("crop", "true");
        intent.putExtra("output", mUriOutput);
        //返回格式
        intent.putExtra("outputFormat", "JPEG");
        intent.putExtra("return-data", false);

        //配置裁剪图片的宽高比例
        if (input.getAspectX() != 0 && input.getAspectY() != 0) {
            intent.putExtra("aspectX", input.getAspectX());
            intent.putExtra("aspectY", input.getAspectY());
        }
        return intent;
    }

    @Override
    public Uri parseResult(int resultCode, @Nullable Intent intent) {
        return mUriOutput;
    }
}

(3) Llamada de registro de imagen recortada

//裁剪图片注册
    private final ActivityResultLauncher<CropImageResult> mActLauncherCrop =
            registerForActivityResult(new CropImage(), result -> {
                //裁剪之后的图片Uri,接下来可以进行压缩处理
            });


/**
     * 开启裁剪图片
     *
     * @param sourceUri 原图片uri
     */
    private void launchImageCrop(Uri sourceUri) {
        mActLauncherCrop.launch(new CropImageResult(sourceUri, 1, 1));
    }

Supongo que te gusta

Origin blog.csdn.net/nsacer/article/details/120156954
Recomendado
Clasificación