手把手教你搭建android项目框架(五)权限工具封装

废话不多说,先看效果

  override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.main_act)
        //单个权限
        requestPermission(Manifest.permission.READ_PHONE_STATE) { g, d, ad ->
            Log.v("granted", "READ_PHONE_STATEis granted $g")
        }
        //组合权限
        requestPermission(
            Manifest.permission.READ_PHONE_STATE,
            Manifest.permission.READ_CONTACTS
        ) { g, d, ad ->
            Log.v("granted", "READ_PHONE_STATE READ_CONTACTS is granted $g")
        }
    }

android6.0以上需要动态请求权限,这里不多废话了,想达到一个简单高效的权限使用方式,就跟我一步一步去封装。
之前比较好用的权限库是rxPermissions,但是由于目前的项目都不太想引入rxjava使用,因此我们用Kotlin封装一个属于自己的权限库。
首先我们可以参考下rxPermissions库,代码如下:

private RxPermissionsFragment getRxPermissionsFragment(Activity activity) {
        RxPermissionsFragment rxPermissionsFragment = findRxPermissionsFragment(activity);
        boolean isNewInstance = rxPermissionsFragment == null;
        if (isNewInstance) {
            rxPermissionsFragment = new RxPermissionsFragment();
            FragmentManager fragmentManager = activity.getFragmentManager();
            fragmentManager
                    .beginTransaction()
                    .add(rxPermissionsFragment, TAG)
                    .commitAllowingStateLoss();
            fragmentManager.executePendingTransactions();
        }
        return rxPermissionsFragment;
    }

这里我们发现他使用了一个fragment作为媒介接收请求结果,无论在activity或者在fragment中请求时,都会将这个fragment添加到当前页面进行处理,这个思路有点类似glide的生命周期监控,我们可以参考这个思路也创建一个fragment进行操作。
整个fragment中代码部分仅有权限申请回调处理和对rxjava的生命周期处理,这里我们借用这个思路创建自己的permissionFragment即可。
由于lifecycle库拥有自带的生命周期处理,因此我们仅需要写出申请权限的回调即可。
代码如下:

class PermissionFragment : Fragment() {
    companion object {
        private const val TAG = "PermissionFragment"
        fun getPermissionFragment(
            activity: FragmentActivity,
            block: (granted: Boolean, deniedList: Array<String>, alwaysDeniedList: Array<String>) -> Unit
        ): PermissionFragment {
            var permissionFragment = findPermissionsFragment(activity)
            if (permissionFragment == null) {
                permissionFragment = PermissionFragment()
                activity.supportFragmentManager.commit(true) {
                    add(permissionFragment, TAG)
                }
            }
            permissionFragment.block = block
            return permissionFragment
        }

        private fun findPermissionsFragment(activity: FragmentActivity): PermissionFragment? {
            return activity.supportFragmentManager.findFragmentByTag(TAG) as? PermissionFragment
        }
    }

    //参数说明
    //granted :申请的权限是否都成功了
   //deniedList:被拒绝的权限
  //alwaysDeniedList:被点了不再询问并拒绝的权限
   //这里的参数回调可以根据需求自行封装。
    private var block: (granted: Boolean, deniedList: Array<String>, alwaysDeniedList: Array<String>) -> Unit =
        { _, _, _ -> }

    private val launcher = registerForActivityResult(
        ActivityResultContracts.RequestMultiplePermissions()
    ) { result ->
        lifecycleScope.launchWhenResumed {
            dealResult(requireActivity(), result, block)
            requireActivity().supportFragmentManager.commit(true) {
                remove(this@PermissionFragment)
            }
        }
    }

    fun requestPermission(
        permissions: Array<String>
    ) {
        lifecycleScope.launchWhenResumed {
            launcher.launch(permissions)
        }
    }

    /**
     * 处理请求权限结果
     */
    private suspend fun dealResult(
        activity: FragmentActivity,
        result: Map<String, Boolean>,
        block: (granted: Boolean, deniedList: Array<String>, alwaysDeniedList: Array<String>) -> Unit,
    ) = withContext(Dispatchers.IO) {
        val allDeniedList = result.filterValues { !it }.mapNotNull { it.key }
        val alwaysDeniedList =
            allDeniedList.filter {
                ActivityCompat.shouldShowRequestPermissionRationale(
                    activity,
                    it
                )
            }
        val deniedList = allDeniedList - alwaysDeniedList.toSet()
        var granted = true
        if (allDeniedList.isNotEmpty()) {
            granted = false
        }
        withContext(Dispatchers.Main) {
            block(granted, deniedList.toTypedArray(), alwaysDeniedList.toTypedArray())
        }
    }
}

到这一步,我们完成了fragment的开发,但是想要更简单的使用,我们需要借助kotlin扩展方法来使用,我们封装一个更方便的扩展方法以便调用,代码如下:

fun LifecycleOwner.requestPermission(
    block: (granted: Boolean, deniedList: Array<String>, alwaysDeniedList: Array<String>) -> Unit,
    permissions: Array<String>
) {
    runCatching {
        when (this@requestPermission) {
            is FragmentActivity -> {
                PermissionFragment.getPermissionFragment(this@requestPermission, block)
                    .requestPermission(permissions)
            }

            is Fragment -> {
                PermissionFragment.getPermissionFragment(
                    this@requestPermission.requireActivity(),
                    block
                )
                    .requestPermission(permissions)
            }

            else -> {
                throw RuntimeException("requestPermission LifecycleOwner必须是activity或fragment")
            }
        }
    }.onFailure {
        block(false, permissions, arrayOf())
    }
}

上述封装了一个初步可用的扩展方法,但是为了更方便使用,我们进一步封装,单个,两个组合,三个组合的方法,更方便使用,代码如下:

//单个权限申请
fun LifecycleOwner.requestPermission(
    p1: String,
    block: (granted: Boolean, deniedList: Array<String>, alwaysDeniedList: Array<String>) -> Unit
) {
    requestPermission(block, arrayOf(p1))
}
//两个个权限组合申请
fun LifecycleOwner.requestPermission(
    p1: String,
    p2: String,
    block: (granted: Boolean, deniedList: Array<String>, alwaysDeniedList: Array<String>) -> Unit
) {
    requestPermission(block, arrayOf(p1, p2))
}

//三个权限组合申请
fun LifecycleOwner.requestPermission(
    p1: String,
    p2: String,
    p3: String,
    block: (granted: Boolean, deniedList: Array<String>, alwaysDeniedList: Array<String>) -> Unit
) {
    requestPermission(block, arrayOf(p1, p2, p3))
}
//四个权限组合申请
fun LifecycleOwner.requestPermission(
    p1: String,
    p2: String,
    p3: String,
    p4: String,
    block: (granted: Boolean, deniedList: Array<String>, alwaysDeniedList: Array<String>) -> Unit
) {
    requestPermission(block, arrayOf(p1, p2, p3, p4))
}

至此,权限Util已经能达到文章开头的使用效果。
//本代码均未完整测试,建议自行测试后使用。
项目地址

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android平台上使用FFmpeg需要进行交叉编译,生成适用于Android的FFmpeg库,并将其打包到apk中。以下是手把手搭建ffmpeg命令行运行环境的步骤: 1.下载NDK 首先需要下载NDK(Native Development Kit),NDK是一个工具包,用于开发C/C++应用程序的原生库。Android Studio自带NDK,也可以从官网下载。 2.下载FFmpeg源代码 从FFmpeg的官网下载源代码,然后解压到本地。 3.配置交叉编译环境 在FFmpeg源代码根目录下创建一个build_android.sh文件,输入以下内容: ```bash #!/bin/bash NDK=$HOME/Android/Sdk/ndk-bundle # NDK路径 SYSROOT=$NDK/platforms/android-21/arch-arm/ # Android SDK路径 TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64 # 工具链路径 function build_one { ./configure \ --prefix=$PREFIX \ --enable-shared \ --disable-static \ --disable-doc \ --disable-ffmpeg \ --disable-ffplay \ --disable-ffprobe \ --disable-ffserver \ --disable-debug \ --disable-network \ --disable-avdevice \ --disable-postproc \ --disable-symver \ --cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \ --target-os=android \ --arch=arm \ --sysroot=$SYSROOT \ --extra-cflags="-Os -fpic $ADDI_CFLAGS" \ --extra-ldflags="$ADDI_LDFLAGS" \ $ADDITIONAL_CONFIGURE_FLAG make make install } CPU=arm PREFIX=$(pwd)/android/$CPU ADDI_CFLAGS="-marm" ADDI_LDFLAGS="" build_one ``` 其中,NDK是NDK的路径,SYSROOT是Android SDK的路径,TOOLCHAIN是工具链的路径。 4.执行交叉编译命令 在终端中输入以下命令: ```bash chmod +x build_android.sh ./build_android.sh ``` 等待编译完成。编译完成后,在FFmpeg源代码根目录下会生成一个android目录,其中包含了交叉编译生成的FFmpeg库。 5.创建Android Studio项目 打开Android Studio,创建一个新项目。在app/build.gradle文件中添加以下代码: ```groovy android { compileSdkVersion 28 defaultConfig { applicationId "com.example.ffmpegdemo" minSdkVersion 21 targetSdkVersion 28 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } externalNativeBuild { cmake { cppFlags "" abiFilters "armeabi-v7a" arguments "-DANDROID_ARM_NEON=TRUE" } } sourceSets.main { jniLibs.srcDirs = ['src/main/jniLibs'] } ndk { abiFilters "armeabi-v7a" } } ``` 其中,externalNativeBuild和ndk是用于指定使用交叉编译生成的库的配置。 6.将FFmpeg库打包到apk中 将交叉编译生成的库复制到项目的app/src/main/jniLibs/armeabi-v7a/目录下。在app/build.gradle文件中添加以下代码: ```groovy android { sourceSets { main { jniLibs.srcDirs = ['src/main/jniLibs'] } } } ``` 然后在终端中输入以下命令: ```bash ./gradlew assembleDebug ``` 等待打包完成。打包完成后,在项目的build/outputs/apk/debug/目录下会生成一个apk文件,其中包含了FFmpeg库。 至此,就完成了搭建ffmpeg命令行运行环境的所有步骤。可以通过在MainActivity中执行FFmpeg命令来测试FFmpeg是否正常工作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值