权限相关
//近似定位(模糊定位)
Manifest.permission.ACCESS_COARSE_LOCATION
//精确定位
Manifest.permission.ACCESS_FINE_LOCATION
定位服务是否开启判断
// 判断定位服务是否开启
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
}
检查是否具有某权限
//检查权限
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)
}
}
/**
* 将私有目录文件拷贝到公共目录,仅针对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")
}
}
}
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>
// 权限申请结果回调
private lateinit var callback: ActivityResultCallback
// 是否多权限
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,
callback: ActivityResultCallback
) {
this.callback = callback
// 是否多权限,回调区分处理
multiPermission = permissions.size > 1
launcher.launch(permissions)
}
}
使用示例:
// 权限请求,在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()
}
}
//注册权限请求
private final ActivityResultLauncher mActLauncherPermission = registerForActivityResult(
new ActivityResultContracts.RequestPermission(), result -> Log.i("zhao", "权限:" + result)
);
//在需要的时候启动权限请求
private void requestPermission() {
mActLauncherPermission.launch(Manifest.permission.CAMERA);
}
//多权限请求
protected final ActivityResultLauncher 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);
}
返回图片Bitmap格式
//拍照
private final ActivityResultLauncher mLauncherCamera = registerForActivityResult(
new ActivityResultContracts.TakePicturePreview(), result -> {
//result为拍摄照片Bitmap格式
});
//启动拍照(注意先检查权限)
//开启拍照,返回结果Bitmap
private void launchCamera() {
mLauncherCamera.launch(null);
}
拍照返回Uri格式
(1)先自定义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
(2)注册调用
//注册调用
private final ActivityResultLauncher
//选取图片
private final ActivityResultLauncher mLauncherAlbum = registerForActivityResult(
new ActivityResultContracts.GetContent(), result -> {
//result为选取的图片的Uri
}
);
//调用相册选择图片
protected void launchAlbum() {
mLauncherAlbum.launch("image/*");
}
private final ActivityResultLauncher mActLauncherAlbum = registerForActivityResult(
new ActivityResultContracts.GetContent(), result -> {
//视频文件路径
String videoPath = result.getPath();
}
);
//选取视频文件(和选取相册类似)
private void launchVideoPick() {
mActLauncherAlbum.launch("video/*");
}
(1)裁剪参数配置类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)裁剪输出配置类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 {
//裁剪后输出的图片文件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)裁剪图片注册调用
//裁剪图片注册
private final ActivityResultLauncher mActLauncherCrop =
registerForActivityResult(new CropImage(), result -> {
//裁剪之后的图片Uri,接下来可以进行压缩处理
});
/**
* 开启裁剪图片
*
* @param sourceUri 原图片uri
*/
private void launchImageCrop(Uri sourceUri) {
mActLauncherCrop.launch(new CropImageResult(sourceUri, 1, 1));
}