PermissionX is an extension Android library that makes Android runtime permission request extremely easy

Overview

PermissionX

中文文档

PermissionX is an extension Android library that makes Android runtime permission request extremely easy. You can use it for basic permission request occasions or handle more complex conditions, like showing rationale dialog or go to app settings for allowance manually.

Quick Setup

Edit your build.gradle file and add below dependency.

repositories {
  google()
  mavenCentral()
}

dependencies {
    implementation 'com.guolindev.permissionx:permissionx:1.5.1'
}

That's all. Now you are ready to go.

Basic Usage

Use PermissionX to request Android runtime permissions is extremely simple.

For example. If you want to request READ_CONTACTS, CAMERA and CALL_PHONE permissions, declared them in the AndroidManifest.xml first.

">
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.permissionx.app">

	<uses-permission android:name="android.permission.READ_CONTACTS" />
	<uses-permission android:name="android.permission.CAMERA" />
	<uses-permission android:name="android.permission.CALL_PHONE" />

manifest>

Then you can use below codes to request.

PermissionX.init(activity)
    .permissions(Manifest.permission.READ_CONTACTS, Manifest.permission.CAMERA, Manifest.permission.CALL_PHONE)
    .request { allGranted, grantedList, deniedList ->
        if (allGranted) {
            Toast.makeText(this, "All permissions are granted", Toast.LENGTH_LONG).show()
        } else {
            Toast.makeText(this, "These permissions are denied: $deniedList", Toast.LENGTH_LONG).show()
        }
    }

Pass any instance of FragmentActivity or Fragment into init method, and specify the permissions that you want to request in the permissions method, then call request method for actual request.

The request result will be callback in the request lambda. allGranted means if all permissions that you requested are granted by user, maybe true or false. grantedList holds all granted permissions and deniedList holds all denied permissions.

Now you can write your own logic in the request lambda to handle the specific cases of your app.

More Usage

As you know, Android provide shouldShowRequestPermissionRationale method to indicate us if we should show a rationale dialog to explain to user why we need this permission. Otherwise user may deny the permissions we requested and checked never ask again option.

To simplify this process, PermissionX provide onExplainRequestReason method. Chain this method before request method, If user deny one of the permissions, onExplainRequestReason method will get callback first. Then you can call showRequestReasonDialog method to explain to user why these permissions are necessary like below.

if (allGranted) { Toast.makeText(this, "All permissions are granted", Toast.LENGTH_LONG).show() } else { Toast.makeText(this, "These permissions are denied: $deniedList", Toast.LENGTH_LONG).show() } } ">
PermissionX.init(activity)
    .permissions(Manifest.permission.READ_CONTACTS, Manifest.permission.CAMERA, Manifest.permission.CALL_PHONE)
    .onExplainRequestReason { scope, deniedList ->
        scope.showRequestReasonDialog(deniedList, "Core fundamental are based on these permissions", "OK", "Cancel")
    }
    .request { allGranted, grantedList, deniedList ->
        if (allGranted) {
            Toast.makeText(this, "All permissions are granted", Toast.LENGTH_LONG).show()
        } else {
            Toast.makeText(this, "These permissions are denied: $deniedList", Toast.LENGTH_LONG).show()
        }
    }

showRequestReasonDialog method will prompt a rationale dialog with the information that second parameter provide. If user click positive button which shows text as third parameter provide, PermissionX will request again with the permissions that first parameter provide.

The fourth parameter as text for negative button is optional. If the denied permissions are necessary, you can ignore the fourth parameter and the dialog will be uncancelable. Which means user must allow these permissions for further usage.

Of course, user still may deny some permissions and checked never ask again option. In this case, each time we request these permissions again will be denied automatically. The only thing we could do is prompt to users they need to allow these permissions manually in app settings for continuation usage. But PermissionX did better.

PermissionX provide onForwardToSettings method for handling this occasion. Chain this method before request method, If some permissions are "denied and never ask again" by user, onForwardToSettings method will get callback. Then you can call showForwardToSettingsDialog method like below.

scope.showForwardToSettingsDialog(deniedList, "You need to allow necessary permissions in Settings manually", "OK", "Cancel") } .request { allGranted, grantedList, deniedList -> if (allGranted) { Toast.makeText(this, "All permissions are granted", Toast.LENGTH_LONG).show() } else { Toast.makeText(this, "These permissions are denied: $deniedList", Toast.LENGTH_LONG).show() } } ">
PermissionX.init(activity)
    .permissions(Manifest.permission.READ_CONTACTS, Manifest.permission.CAMERA, Manifest.permission.CALL_PHONE)
    .onExplainRequestReason { scope, deniedList ->
        scope.showRequestReasonDialog(deniedList, "Core fundamental are based on these permissions", "OK", "Cancel")
    }
    .onForwardToSettings { scope, deniedList ->
        scope.showForwardToSettingsDialog(deniedList, "You need to allow necessary permissions in Settings manually", "OK", "Cancel")
    }
    .request { allGranted, grantedList, deniedList ->
        if (allGranted) {
            Toast.makeText(this, "All permissions are granted", Toast.LENGTH_LONG).show()
        } else {
            Toast.makeText(this, "These permissions are denied: $deniedList", Toast.LENGTH_LONG).show()
        }
    }

The parameters in onForwardToSettings method are similar with showRequestReasonDialog method. When user click positive button, PermissionX will forward to the settings page of your app and user can turn on the necessary permissions very quickly. When user switch back to app, PermissionX will request the necessary permissions again automatically.

Explain Before Request

It is always a good manner to show the rationale dialog and explain to users why you need these permissions before you actually request them.

To do that with PermissionX is quite simple. Just use explainReasonBeforeRequest method like below.

PermissionX.init(activity)
    .permissions(Manifest.permission.READ_CONTACTS, Manifest.permission.CAMERA, Manifest.permission.CALL_PHONE)
    .explainReasonBeforeRequest()
    ...

Now everything works like charm.

Dark Theme

The rationale dialog provided by PermissionsX support Android dark theme automatically. If you change your device into dark theme, everything just works great.

License

Copyright (C) guolin, PermissionX Open Source Project

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Comments
  • request result allGranted issue

    request result allGranted issue

    allGranted will return true even if permissions are not allowed after init called several times in a row.

    To do actions after permissions are granted, I work around it by comparing grantedList and permissionList.

    opened by frengky-sinaga 14
  • 通讯录没有给权限,然后PermissionX却回调回来权限是通过的

    通讯录没有给权限,然后PermissionX却回调回来权限是通过的

    最近在开发关于读取通讯录的一款App,在开发的过程当中,先使用了PermissionX进行请求可以读写通讯录的操作权限

    PermissionUtil.checkContacts(activity,(allGranted, grantedList, deniedList) -> {
                                    if (allGranted){
                                       Log.i(TAG,"权限通过");
                                    }
                                });
    
    • Manifest.permission.READ_CONTACTS
    • Manifest.permission.WRITE_CONTACTS
    • Manifest.permission.GET_ACCOUNTS

    主要读取了以上的权限,但是回调回来的结果竟然是通过,导致项目多次无法正常的运行

    现在又抓紧时间使用了其他的方式进行了权限的请求,还望做着可以查一下为什么会出现这样的问题

    opened by zhouhuandev 13
  • java.lang.IllegalStateException: FragmentManager is already executing transactions

    java.lang.IllegalStateException: FragmentManager is already executing transactions

    在activity使用,代码如下:

    private fun requestFloatPermission() {
            PermissionX.init(this)
                .permissions(Manifest.permission.SYSTEM_ALERT_WINDOW)
                .onExplainRequestReason { scope, deniedList, beforeRequest ->
                    val message = "您的手机没有授予悬浮窗权限,请开启后再试"
                    val dialog = CustomDialogFragment(message, deniedList)
                    scope.showRequestReasonDialog(dialog)
                }
                .onForwardToSettings { scope, deniedList ->
                    val message = "您的手机没有授予悬浮窗权限,请跳到设置页面开启后再试"
                    val dialog = CustomDialogFragment(message, deniedList)
                    scope.showForwardToSettingsDialog(dialog)
                }
                .request { allGranted, grantedList, deniedList ->
                    if (allGranted) {
                        Toast.makeText(this, "所有申请的权限都已通过", Toast.LENGTH_SHORT).show()
                    } else {
                        Toast.makeText(this, "您拒绝了如下权限:$deniedList", Toast.LENGTH_SHORT).show()
                    }
                }
        }
    
    • 点击请求->点击开启->跳到悬浮窗设置界面后按返回键
    • [

    https://user-images.githubusercontent.com/22569670/138995112-17163417-e770-4897-b548-3fb764c1c0bb.mp4

    ] src.zip

    opened by weileifrank 11
  • OPPO Ace2 ColorOS Android 11只有存储权限申请通过,其他权限没有触发提示

    OPPO Ace2 ColorOS Android 11只有存储权限申请通过,其他权限没有触发提示

    binding.makeRequestBtn.setOnClickListener {
               PermissionX.init(this)
                   .permissions(
                   Manifest.permission.CAMERA,
                       Manifest.permission.ACCESS_FINE_LOCATION,
                       Manifest.permission.RECORD_AUDIO,
    //                    Manifest.permission.READ_CALENDAR,
    //                    Manifest.permission.READ_CALL_LOG,
    //                    Manifest.permission.READ_CONTACTS,
                       Manifest.permission.READ_PHONE_STATE,
    //                    Manifest.permission.BODY_SENSORS,
    //                    Manifest.permission.ACTIVITY_RECOGNITION,
                       Manifest.permission.ACCESS_COARSE_LOCATION,
                       Manifest.permission.ACCESS_BACKGROUND_LOCATION,
    //                    Manifest.permission.SEND_SMS,
                       Manifest.permission.READ_EXTERNAL_STORAGE
                   )
                   .onExplainRequestReason { scope, deniedList, beforeRequest ->
                       val message = "PermissionX needs following permissions to continue"
                       scope.showRequestReasonDialog(deniedList, message, "Allow", "Deny")
    //                    val message = "Please allow the following permissions in settings"
    //                    val dialog = CustomDialogFragment(message, deniedList)
    //                    scope.showRequestReasonDialog(dialog)
                   }
                   .onForwardToSettings { scope, deniedList ->
                       val message = "Please allow following permissions in settings"
                       val dialog = CustomDialogFragment(message, deniedList)
                       scope.showForwardToSettingsDialog(dialog)
                   }
                   .request { allGranted, grantedList, deniedList ->
                       if (allGranted) {
                           Toast.makeText(activity, "All permissions are granted", Toast.LENGTH_SHORT).show()
                       } else {
                           Toast.makeText(activity, "The following permissions are denied:$deniedList", Toast.LENGTH_SHORT).show()
                       }
                   }
           }
    

    就一项储存权限打开了,其他权限都没显示提示,都处于拒绝状态,不能用,回调All permissions are granted 了

    opened by LiWeiQiangAndroid 11
  • 我想请求联系人的读写权限,回调直接返回的拒绝

    我想请求联系人的读写权限,回调直接返回的拒绝

    PermissionX.init(topActivity) .permissions(Manifest.permission.READ_CONTACTS, Manifest.permission.WRITE_CONTACTS) .request { allGranted, _, deniedList -> if (allGranted) { getLocalContacts() } else { toastMsg.value = "没有权限:${deniedList}" LogUtils.e("Without Permission:${deniedList}") } }

    opened by lucers 10
  • android.permission.ACCESS_BACKGROUND_LOCATION 在华为手机8.1.0上崩溃

    android.permission.ACCESS_BACKGROUND_LOCATION 在华为手机8.1.0上崩溃

    系统版本:Android 8.1.0,level 27 ROM :HuaWei/EMOTION crash 标题 : android.content.pm.PackageManager$NameNotFoundException android.permission.ACCESS_BACKGROUND_LOCATION com.permissionx.guolindev.dialog.a.d(SourceFile:4)

    详细日志: java.lang.RuntimeException:Failure delivering result ResultInfo{who=@android:requestPermissions:, request=1194976313, result=-1, data=Intent { act=android.content.pm.action.REQUEST_PERMISSIONS (has extras) }} to activity {xxx.xxxx.android/com.xxxxxx.main.MainActivity}: android.content.pm.PackageManager$NameNotFoundException: android.permission.ACCESS_BACKGROUND_LOCATION 2 android.app.ActivityThread.deliverResults(ActivityThread.java:5042) 3 ...... 4 Caused by: 5 android.content.pm.PackageManager$NameNotFoundException:android.permission.ACCESS_BACKGROUND_LOCATION 6 android.app.ApplicationPackageManager.getPermissionInfo(ApplicationPackageManager.java:330) 7 com.permissionx.guolindev.dialog.a.d(SourceFile:4) 8 com.permissionx.guolindev.dialog.a.onCreate(SourceFile:4) 9 android.app.Dialog.dispatchOnCreate(Dialog.java:516) 10 android.app.Dialog.show(Dialog.java:382) 11 com.permissionx.guolindev.request.e.i(SourceFile:6) 12 com.permissionx.guolindev.request.e.j(SourceFile:2) 13 com.permissionx.guolindev.request.d.a(SourceFile:1) 14 base.sys.utils.w.j(SourceFile:7) 15 base.sys.utils.w.g(Unknown Source:0) 16 base.sys.utils.a.a(Unknown Source:0) 17 com.permissionx.guolindev.request.InvisibleFragment.r(SourceFile:17) 18 com.permissionx.guolindev.request.InvisibleFragment.onRequestPermissionsResult(SourceFile:2) 19 androidx.fragment.app.FragmentManager$11.onActivityResult(SourceFile:14) 20 androidx.fragment.app.FragmentManager$11.onActivityResult(SourceFile:1) 21 androidx.activity.result.ActivityResultRegistry.doDispatch(SourceFile:3) 22 androidx.activity.result.ActivityResultRegistry.dispatchResult(SourceFile:3) 23 androidx.activity.ComponentActivity.onRequestPermissionsResult(SourceFile:4) 24 androidx.fragment.app.FragmentActivity.onRequestPermissionsResult(SourceFile:2) 25 android.app.Activity.dispatchRequestPermissionsResult(Activity.java:7786) 26 android.app.Activity.dispatchActivityResult(Activity.java:7637) 27 android.app.ActivityThread.deliverResults(ActivityThread.java:5038) 28 android.app.ActivityThread.handleSendResult(ActivityThread.java:5086) 29 android.app.ActivityThread.-wrap20(Unknown Source:0) 30 android.app.ActivityThread$H.handleMessage(ActivityThread.java:2071) 31 android.os.Handler.dispatchMessage(Handler.java:109) 32 android.os.Looper.loop(Looper.java:166) 33 android.app.ActivityThread.main(ActivityThread.java:7555) 34 java.lang.reflect.Method.invoke(Native Method)

    翻阅了代码发现: // If app runs under Android Q, there's no ACCESS_BACKGROUND_LOCATION permissions. // We remove it from request list, but will append it to the request callback as denied permission.

    opened by tianjinrui 8
  • 空指针异常

    空指针异常

    首先说明框架没问题,是我用的问题,由于水平较低,不知道怎么处理是比较稳妥的,所以提个问题。Demo中 是在按钮点击时间里面去应用的框架,CustomDialogFragment 弹窗是没问题的,但是我们需求是启动activity后 去检测权限,所以我直接把代码放到onCreate 中, @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main_java); PermissionX.init(MainJavaActivity.this) .permissions(Manifest.permission.WRITE_EXTERNAL_STORAGE) .explainReasonBeforeRequest() .onExplainRequestReason(new ExplainReasonCallbackWithBeforeParam() { @Override public void onExplainReason(ExplainScope scope, List deniedList, boolean beforeRequest) { CustomDialogFragment dialog = new CustomDialogFragment("请允许权限选择", deniedList); scope.showRequestReasonDialog(dialog); } }).onForwardToSettings(new ForwardToSettingsCallback() { @Override public void onForwardToSettings(ForwardScope scope, List deniedList) { CustomDialogFragment dialog = new CustomDialogFragment("请允许权限选择,去设置", deniedList); scope.showForwardToSettingsDialog(dialog); } }).request(new RequestCallback() { @Override public void onResult(boolean allGranted, List grantedList, List deniedList) { if (allGranted) { Toast.makeText(MainJavaActivity.this, "All permissions are granted", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(MainJavaActivity.this, "The following permissions are denied:" + deniedList, Toast.LENGTH_SHORT).show(); } } }); } 但是获取控件为空 View positiveButton = dialogFragment.getPositiveButton(); View negativeButton = dialogFragment.getNegativeButton(); 请教郭神这种情况怎么处理比较好

    bug question 
    opened by duronggang 8
  • 权限申请禁止后去设置返回后,创建showForwardToSettingsDialog会闪烁

    权限申请禁止后去设置返回后,创建showForwardToSettingsDialog会闪烁

        PermissionX.init(this@AddSoundsActivity)
            .permissions(Manifest.permission.RECORD_AUDIO)
            .onExplainRequestReason { scope, deniedList ->
                scope.showRequestReasonDialog(
                    deniedList,
                    CONST_PERMISSION_RECORD_AUDIO,
                    CONST_PERMISSION_OK,
                    CONST_PERMISSION_CANCEL
                )
            }
            .onForwardToSettings { scope, deniedList ->
                scope.showForwardToSettingsDialog(
                    deniedList,
                    CONST_PERMISSION_TIP,
                    CONST_PERMISSION_SETTING,
                    CONST_PERMISSION_CANCEL
                )
            }
            .request { allGranted, _, _ ->
                if (allGranted) {
                    mIatDialog?.let {
                        it.setListener(mRecognizerDialogListener)
                        it.show()
                        val txt = it.window?.decorView?.findViewWithTag<TextView>("textlink")
                        if (txt != null) txt.text = ""
                    }
                }
            }
    

    这个代码申请权限,如果选择拒绝,然后showForwardToSettingsDialog,然后通过Dialog选择去设置权限,去设置后什么也不操作,直接返回会闪烁

    opened by sjw903 7
  • 你好!过神!小米 Redmi 4A 申请权限异常

    你好!过神!小米 Redmi 4A 申请权限异常

    1.当拒绝权限之后,跳入设置,打开权限,返回到应用时会有开启权限的弹窗提示,此时继续拒绝,则会导致应用崩溃报异常 2.具体看了下原因,因为再次拒绝!grantedPermissions 对象为空,导致界面崩溃 Caused by: java.lang.NullPointerException: Attempt to read from field 'java.util.Set com.permissionx.guolindev.request.PermissionBuilder.grantedPermissions' on a null object reference at com.permissionx.guolindev.request.InvisibleFragment.onRequestNormalPermissionsResult(InvisibleFragment.java:125) at com.permissionx.guolindev.request.InvisibleFragment.onRequestPermissionsResult(InvisibleFragment.java:97) at androidx.fragment.app.FragmentActivity.onRequestPermissionsResult(FragmentActivity.java:769) at android.app.Activity.dispatchRequestPermissionsResult(Activity.java:6634) at android.app.Activity.dispatchActivityResult(Activity.java:6512) at android.app.ActivityThread.deliverResults(ActivityThread.java:3734) at android.app.ActivityThread.handleSendResult(ActivityThread.java:3781)  at android.app.ActivityThread.access$1500(ActivityThread.java:153)  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1424)  at android.os.Handler.dispatchMessage(Handler.java:102)  at android.os.Looper.loop(Looper.java:154)  at android.app.ActivityThread.main(ActivityThread.java:5523)  at java.lang.reflect.Method.invoke(Native Method)  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:739)  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:629) 

    opened by z244370114 7
  • 【崩溃BUG】申请两个权限,将其中一个”禁止后不再提醒“,然后去应用设置将被允许的权限也禁止,再返回App直接崩溃

    【崩溃BUG】申请两个权限,将其中一个”禁止后不再提醒“,然后去应用设置将被允许的权限也禁止,再返回App直接崩溃

    复现操作: (1) 点击按钮弹出RequestReasonDialog,点击确定。 (2) 允许存储权限,拒绝相机权限。此时会再次弹出RequestReasonDialog。 (3) 点击确定,然后点击禁止后不再提示。此时会弹出ForwardToSettingsDialog。 (4) 点击确定,然后在应用程序权限设置中禁止存储权限。 (5) 再次返回App,App崩溃。

    核心代码如下: PermissionX.init(this) .permissions(Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA) .explainReasonBeforeRequest() .onExplainRequestReason(new ExplainReasonCallback() { @Override public void onExplainReason(ExplainScope scope, List deniedList) { String message = "该功能需要您同意以下权限才能正常使用"; scope.showRequestReasonDialog(deniedList, message, "确定", "取消"); } }) .onForwardToSettings(new ForwardToSettingsCallback() { @Override public void onForwardToSettings(ForwardScope scope, List deniedList) { scope.showForwardToSettingsDialog(deniedList, "您需要去应用程序设置中手动开启以下权限", "确定", "取消"); } }) .request(new RequestCallback() { @Override public void onResult(boolean allGranted, List grantedList, List deniedList) { if (allGranted) { } } });

    opened by MapleDS 7
  • 奔溃闪退必先( FragmentManager is already executing transactions)

    奔溃闪退必先( FragmentManager is already executing transactions)

    版本:com.guolindev.permissionx:permissionx:1.6.4

    java.lang.IllegalStateException: FragmentManager is already executing transactions at androidx.fragment.app.FragmentManager.ensureExecReady(FragmentManager.java:1931) at androidx.fragment.app.FragmentManager.execSingleAction(FragmentManager.java:1967) at androidx.fragment.app.BackStackRecord.commitNowAllowingStateLoss(BackStackRecord.java:311) at com.permissionx.guolindev.request.PermissionBuilder.getInvisibleFragment(PermissionBuilder.kt:99) at com.permissionx.guolindev.request.PermissionBuilder.requestNow(PermissionBuilder.kt:427) at com.permissionx.guolindev.request.RequestNormalPermissions.request(RequestNormalPermissions.kt:53) at com.permissionx.guolindev.request.RequestChain.runTask$permissionx_release(RequestChain.kt:51) at com.permissionx.guolindev.request.PermissionBuilder.startRequest(PermissionBuilder.kt:537) at com.permissionx.guolindev.request.PermissionBuilder.request(PermissionBuilder.kt:287)

    opened by 474246820 6
  • Fragment中使用崩溃

    Fragment中使用崩溃

    版本:1.6.1 手机型号:Pixel 5、小米12SU、小米13、三星,都是Android 13的机型 现象描述:在Fragment onViewCreated中使用请求权限出现崩溃 崩溃日志:

    Process Name: 'com.example.demo'
    Thread Name: 'main'
    Back traces starts.
    java.lang.IllegalStateException: FragmentManager is already executing transactions
    	at androidx.fragment.app.FragmentManager.ensureExecReady(FragmentManager.java:80)
    	at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:0)
    	at androidx.fragment.app.FragmentManager.handleOnBackPressed(FragmentManager.java:1)
    	at androidx.fragment.app.FragmentManager$1.handleOnBackPressed(FragmentManager.java:2)
    	at androidx.activity.OnBackPressedDispatcher.b(OnBackPressedDispatcher.java:24)
    	at com.qmuiteam.qmui.arch.QMUIFragment.u(QMUIFragment.java:4)
    	at com.xsure.xsurenc.ui.device.connect.BleConfigureFragment$$InternalSyntheticLambda$2$340dd378563ba7cc58a1c6e6f98c880db3bb766ebf82481d2ab95733ff4bdb13$2.onResult(BleConfigureFragment.java:0)
    	at com.xsure.xsurenc.ui.device.connect.BleConfigureFragment.startScanAfterCheckPermission$lambda-2(BleConfigureFragment.java:0)
    	at com.permissionx.guolindev.request.BaseTask.finish(BaseTask.java:0)
    	at com.permissionx.guolindev.request.RequestInstallPackagesPermission.request(RequestInstallPackagesPermission.java:0)
    	at com.permissionx.guolindev.request.BaseTask.finish(BaseTask.java:0)
    	at com.permissionx.guolindev.request.RequestManageExternalStoragePermission.request(RequestManageExternalStoragePermission.java:0)
    	at com.permissionx.guolindev.request.BaseTask.finish(BaseTask.java:0)
    	at com.permissionx.guolindev.request.RequestWriteSettingsPermission.request(RequestWriteSettingsPermission.java:0)
    	at com.permissionx.guolindev.request.BaseTask.finish(BaseTask.java:0)
    	at com.permissionx.guolindev.request.RequestSystemAlertWindowPermission.request(RequestSystemAlertWindowPermission.java:0)
    	at com.permissionx.guolindev.request.BaseTask.finish(BaseTask.java:0)
    	at com.permissionx.guolindev.request.RequestBackgroundLocationPermission.request(RequestBackgroundLocationPermission.java:0)
    	at com.permissionx.guolindev.request.BaseTask.finish(BaseTask.java:0)
    	at com.permissionx.guolindev.request.PermissionBuilder.showHandlePermissionDialog(PermissionBuilder.java:0)
    	at com.permissionx.guolindev.request.PermissionBuilder.showHandlePermissionDialog(PermissionBuilder.java:0)
    	at com.permissionx.guolindev.request.ExplainScope.b(ExplainScope.java:15)
    	at com.xsure.xsurenc.ui.device.connect.BleConfigureFragment.startScanAfterCheckPermission$lambda-0(BleConfigureFragment.java:0)
    	at com.xsure.xsurenc.ui.device.connect.BleConfigureFragment$$InternalSyntheticLambda$2$340dd378563ba7cc58a1c6e6f98c880db3bb766ebf82481d2ab95733ff4bdb13$0.onExplainReason(BleConfigureFragment.java:0)
    	at com.permissionx.guolindev.request.RequestNormalPermissions.request(RequestNormalPermissions.java:0)
    	at com.permissionx.guolindev.request.PermissionBuilder.request(PermissionBuilder.java:0)
    	at com.permissionx.guolindev.request.RequestChain.runTask$permissionx_release(RequestChain.java:0)
    	at com.xsure.xsurenc.ui.device.connect.BleConfigureFragment.startScanAfterCheckPermission(BleConfigureFragment.java:0)
    	at com.xsure.xsurenc.ui.device.connect.BleConfigureFragment.requestScanDevice(BleConfigureFragment.java:0)
    	at com.xsure.xsurenc.ui.device.connect.BleConfigureFragment.initView(BleConfigureFragment.java:0)
    	at com.xsure.xsurenc.ui.device.connect.BleConfigureFragment.initView(BleConfigureFragment.java:0)
    	at com.xsure.xsurenc.base.BaseFragment.onViewCreated(BaseFragment.java:0)
    	at com.qmuiteam.qmui.arch.QMUIFragment.onViewCreated(QMUIFragment.java:16)
    	at com.xsure.xsurenc.base.BaseFragment.onViewCreated(BaseFragment.java:24)
    	at androidx.fragment.app.Fragment.performViewCreated(Fragment.java:4)
    	at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:0)
    	at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:120)
    	at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:230)
    	at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:81)
    	at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:21)
    	at androidx.fragment.app.FragmentManager$4.run(FragmentManager.java:3)
    	at android.os.Handler.handleCallback(Handler.java:942)
    	at android.os.Handler.dispatchMessage(Handler.java:99)
    	at android.os.Looper.loopOnce(Looper.java:210)
    	at android.os.Looper.loop(Looper.java:299)
    	at android.app.ActivityThread.main(ActivityThread.java:8234)
    	at java.lang.reflect.Method.invoke(Method.java)
    	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:559)
    	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:954)
    Back traces ends.
    

    代码:

    companion object {
        const val TAG = "BleConfigureFragment"
        private val OBLIGATORY_PERMISSIONS = arrayOf(
            Manifest.permission.BLUETOOTH_SCAN,
            Manifest.permission.BLUETOOTH_CONNECT,
            Manifest.permission.BLUETOOTH_ADVERTISE
        )
    
        @JvmStatic
        fun newInstance(bundle: Bundle?) = BleConfigureFragment().apply {
            arguments = bundle
        }
    }
    private fun startScanAfterCheckPermission() {
        if (PermissionUtil.hasObligatoryPermissions(requireContext(), *OBLIGATORY_PERMISSIONS)) {
            startScan()
            return
        }
        PermissionX.init(this).permissions(*OBLIGATORY_PERMISSIONS)
            .explainReasonBeforeRequest()
            .onExplainRequestReason { scope, deniedList ->
                scope.showRequestReasonDialog(
                    deniedList,
                    getString(R.string.permission_dialog_message_request_location_reason),
                    getString(R.string.permission_dialog_action_positive),
                    getString(R.string.permission_dialog_action_negative)
                )
            }
            .onForwardToSettings { scope, deniedList ->
                scope.showForwardToSettingsDialog(
                    deniedList,
                    getString(R.string.permission_dialog_message_forward_setting),
                    getString(R.string.common_ok),
                    getString(R.string.common_cancel)
                )
            }
            .request { allGranted, grantedList, deniedList ->
                if (allGranted) {
                    startScan()
                } else {
                    popBackStack()
                }
            }
    }
    
    opened by fuhaodev 0
  •  java.lang.NullPointerException

    java.lang.NullPointerException

    Exception java.lang.NullPointerException: Attempt to invoke virtual method 'int android.content.Context.checkPermission(java.lang.String, int, int)' on a null object reference at androidx.core.content.ContextCompat.checkSelfPermission (ContextCompat.java) at com.permissionx.guolindev.PermissionX.isGranted (PermissionX.java) at com.permissionx.guolindev.request.InvisibleFragment.onRequestNormalPermissionsResult (InvisibleFragment.java) at com.permissionx.guolindev.request.InvisibleFragment.access$onRequestNormalPermissionsResult (InvisibleFragment.java) at com.permissionx.guolindev.request.InvisibleFragment$requestNormalPermissionLauncher$1$1.invoke (InvisibleFragment.java) at com.permissionx.guolindev.request.InvisibleFragment$requestNormalPermissionLauncher$1$1.invoke (InvisibleFragment.java) at com.permissionx.guolindev.request.InvisibleFragment.postForResult$lambda-8 (InvisibleFragment.java) at com.permissionx.guolindev.request.InvisibleFragment.$r8$lambda$5smUx0LTHxWnAIIE5s8Iv2EsV18 (InvisibleFragment.java) at com.permissionx.guolindev.request.InvisibleFragment$$InternalSyntheticLambda$0$f59db7f427491b6f872545e585905152d28debc33d2f2a98eae067cb4537c2d9$0.run (InvisibleFragment.java) at android.os.Handler.handleCallback (Handler.java:883) at android.os.Handler.dispatchMessage (Handler.java:100) at android.os.Looper.loop (Looper.java:264) at android.app.ActivityThread.main (ActivityThread.java:7581) at java.lang.reflect.Method.invoke (Method.java) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:492) at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:980)

    opened by yz1309 1
  • 希望增加支持在一个权限申请回调里面接着申请另外一个权限的功能

    希望增加支持在一个权限申请回调里面接着申请另外一个权限的功能

    https://github.com/guolindev/PermissionX/issues/188

    这个是系统限制,如果你一次性请求多个权限,那么就是会需要权限都处理完了之后一次性回调结果。

    如果你想要每请求一个权限就有一个回调出来,那么可以把权限单个申请,等前一个回调的结果出来了再申请下一个权限。

    ========================================================== 现在权限合规一般需要一个权限申请同时对应显示一个说明该权限的弹窗,如果有两个权限同时需要申请,我现在是在第一个权限申请完的回调里面接着申请另外一个权限,我发现第二个权限申请的回调无法接收到了。通过了解源码,发现第一个权限申请完后,这个权限责任链全部完成了,会先回调onResult,然后再endReuest,会导致第二个权限申请后,对应的InvisibleFrgament在endRequest里面被移除了,导致第二个权限回调无反应,当然这个需求也是很奇葩的

    opened by 523931340 1
  • Could we please have tags?

    Could we please have tags?

    Nice library, small suggestion. Can we please have tags on release commits so we know what code changes on each release.

    Adding the change log to the GitHub release would be good too. 😄

    opened by nicbell 0
Owner
Lin Guo
Google Developer Expert for Android
Lin Guo
Android Applications Permission Scanner

An Android Application Scanner built using Java on Android Studio. It basically scans all the applications and lets you know if any application is using your camera or microphone. If it does then it tells you to use that application for some time so that it could track it and let you know if there is any privacy concern

Sameet Asadullah 3 Aug 18, 2022
A runtime mobile application analysis toolkit with a Web GUI, powered by Frida, written in Python.

___ ___ / | \ ____ __ __ ______ ____ / ~ \/ _ \| | \/ ___// __ \ \ Y ( <_> )

NCC Group Plc 1.2k Dec 21, 2022
Burp extension to create target specific and tailored wordlist from burp history.

Burp extension to create target specific and tailored wordlist from burp history.

Dexter0us 173 Jan 2, 2023
CLI tool for decompiling Android apps to Java. It does resources! It does Java! Its real easy!

Easy-as-pie Android Decompiler Why One stop shop I got pretty tired of decompiling Android apps with a bunch of steps that I had to remember all the t

Alex Davis 619 Dec 27, 2022
Easy to use cryptographic framework for data protection: secure messaging with forward secrecy and secure data storage. Has unified APIs across 14 platforms.

Themis provides strong, usable cryptography for busy people General purpose cryptographic library for storage and messaging for iOS (Swift, Obj-C), An

Cossack Labs 1.6k Dec 29, 2022
Simple API to perform AES encryption on Android. This is the Android counterpart to the AESCrypt library Ruby and Obj-C (with the same weak security defaults :( ) created by Gurpartap Singh. https://github.com/Gurpartap/aescrypt

AESCrypt-Android Simple API to perform AES encryption on Android with no dependancies. This is the Android counterpart to the AESCrypt library Ruby an

Scott Alexander-Bown 636 Dec 18, 2022
Signal Protocol library for Java/Android

Overview A ratcheting forward secrecy protocol that works in synchronous and asynchronous messaging environments. PreKeys This protocol uses a concept

Signal 1.8k Dec 24, 2022
Grab’n Run, a simple and effective Java Library for Android projects to secure dynamic code loading.

Grab’n Run, a simple and effective Java Library for Android projects to secure dynamic code loading.

Luca Falsina 418 Dec 29, 2022
🔓 Kotlin version of the popular google/easypermissions wrapper library to simplify basic system permissions logic on Android M or higher.

?? Kotlin version of the popular google/easypermissions wrapper library to simplify basic system permissions logic on Android M or higher.

Madalin Valceleanu 327 Dec 30, 2022
MiHawk 🦅👁️ is simple and secure 🔒 Android Library to store and retrieve pair of key-value data with encryption , internally it use jetpack DataStore Preferences 💽 to store data.

MiHawk MiHawk ?? ??️ is simple and secure ?? Android Library to store and retrieve pair of key-value data with encryption , internally it use jetpack

Nedal Hasan Ibrahem 5 Sep 3, 2022
A simple library that can help you detect if you app is modded or tampered with

Android Tamper Detector A simple library that can help you detect if you app is modded or tampered with. This adds a security level that makes it diff

Mukesh Solanki 130 Nov 14, 2022
Dex manipulation library

dexterity Description dexterity is a C library intended for manipulation and analysis of DEX files. It has python bindings for all basic DEX structure

Rodrigo Chiossi 93 Nov 25, 2022
If you have trouble pinning your custom icon to Launcher dynamically, try this library

CustomIconHelperX If you have trouble pinning your custom icon to Launcher dynam

Valentine Liao 1 Jan 4, 2022
BlackDex is an Android unpack tool, it supports Android 5.0~12 and need not rely to any environment. BlackDex can run on any Android mobile phones or emulators, you can unpack APK File in several seconds.

BlackDex is an Android unpack tool, it supports Android 5.0~12 and need not rely to any environment. BlackDex can run on any Android mobile phones or emulators, you can unpack APK File in several seconds.

null 4.3k Jan 2, 2023
A collection of android security related resources

android-security-awesome A collection of android security related resources. Tools Academic/Research/Publications/Books Exploits/Vulnerabilities/Bugs

Ashish Bhatia 6.6k Jan 5, 2023
a version of the official Android openssl setup to build standalone for use in app

OpenSSL on the Android platform. --- The code in this directory is based on $OPENSSL_VERSION in the file openssl.version. See patches/README for more

Guardian Project 371 Dec 8, 2022
A port of gnupg to Android (UNMAINTAINED!)

Gnu Privacy Guard for Android A port of the whole GnuPG 2.1 suite to Android. If you are using these tools in your own apps, we'd love to hear about i

Guardian Project 282 Jan 7, 2023
OpenPGP for Android

APG (Android Privacy Guard) APG originally brought email encryption to the Android platform. In recent years the project has fallen asleep, but a lot

Thialfihar 234 Dec 30, 2022