写这篇文章的原因主要是为了加深下印象吧,也方便自己后来的复习,同时呢,我之前运行权限也是用的rxpermission来进行权限申请的,但是看了这篇文章fragment申请权限后,除了学到了fragment的骚操作,自己还在这篇文章的基础上进行了封装,使得权限申请更为方便,甚至比rxpermissiom的权限申请更少了些许代码
因为最近自己在学习kotlin,所以我这里就改用了kotlin来写了,这也算活学活用吧
/**
* Created by alan on 2019/4/4 14:50
*/
@SuppressLint("CheckResult", "NewApi")
class PermissionFragment : Fragment() {
private val callBacks = SparseArray()
private val eachCallBacks = SparseArray()
private var pers: Array? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//在activity被重新创建的时候,保证fragment实例不会被重新创建
retainInstance = true
}
/**
* 一次性请求多个权限并且全部被授权才会回调ongranded
*/
fun requestPermissons(permission: Array, callback: PermissiomCallBack.CallBack) {
pers = permission
var permissions = filter(permission).toTypedArray()
if (permissions.isEmpty()) return
//判断权限是否被禁止且不再询问
if (isNeverAsk(permissions)) {
showOpenPermissionSettingDialog(permissions)
return
}
val requestCode: Int = generateCode()
callBacks.put(requestCode, callback)
requestPermissions(permissions, requestCode)
}
/*
* 每个权限的请求结果都会被封装到permission类中并且回调到callback的回调方法中
* */
fun requestEachPermission(permission: Array, callback: PermissiomCallBack.EachCallBack) {
pers = permission
var permissions = filter(permission).toTypedArray()
if (permissions.isEmpty()) return
if (isNeverAsk(permissions)) {
showOpenPermissionSettingDialog(permissions)
return
}
val requestCode: Int = generateCode()
eachCallBacks.put(requestCode, callback)
requestPermissions(permissions, requestCode)
}
/*
* 弹出打开被禁掉且不再询问的权限的对话框
* */
private fun showOpenPermissionSettingDialog(permission: Array) {
SettingDialog.getInstance().setContent("需要打开${PermissionToChinese.toChinese(permission[0])}权限才可以使用该功能").setOnClickListener(object : SettingDialog.OnClickListener {
override fun onPositive() {
jumbToPermissionSetting()
}
}).show(activity!!.supportFragmentManager, "SettingDialog")
}
/*
* 去权限设置页面
* */
private fun jumbToPermissionSetting() {
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
val uri = Uri.fromParts("package", activity?.packageName, null)
intent.data = uri
startActivityForResult(intent, 1001)
}
/*
* 权限是否被设置了不再询问
* */
private fun isNeverAsk(permissions: Array): Boolean {
var isNever = false
for (per in permissions) {
if (!activity!!.shouldShowRequestPermissionRationale(per)) {
isNever = true
break
}
}
return isNever
}
/**
* 生成随机的requestcode
*/
private fun generateCode(): Int {
//生成五位随机数
var code: Int = Random().nextInt(10000)
var times = 0
do {
times++
if (callBacks.get(code) == null) break
} while (10 > times)
return code
}
/**
* 每个权限单独回调到callback中
*/
private fun handleEachPermission(requestCode: Int, permissions: Array, grantResults: IntArray) {
var callBack = eachCallBacks.get(requestCode)
if (callBack == null) return
eachCallBacks.remove(requestCode)
val permission = Permission()
//android版本小于6.0
if (Build.VERSION.SDK_INT < M) {
allGranded(callBack, permissions)
return
}
for ((index, e) in grantResults.withIndex()) {
permission.name = permissions[index].substring(permissions[index].lastIndexOf(".") + 1)
permission.isGranded = if (e == PackageManager.PERMISSION_DENIED) false else true
callBack.onResult(permission)
}
}
/*
* 权限全部被授权
* */
private fun allGranded(callBack: PermissiomCallBack.EachCallBack, permissions: Array) {
permissions.forEach { s ->
callBack.onResult(Permission(s.substring(s.lastIndexOf(".") + 1), true))
}
}
/**
* 全部申请结果通过回调ongranded 否则 回调ondenied
*/
private fun hadlePermissionCallBack(requestCode: Int, grantResults: IntArray) {
val callBack = callBacks.get(requestCode)
if (callBack == null) return
callBacks.remove(requestCode)
if (Build.VERSION.SDK_INT < M) {
callBack.onGranded()
return
}
grantResults.forEach { i ->
if (i != PackageManager.PERMISSION_GRANTED) {
callBack.onDenied()
return
}
}
callBack.onGranded()
}
/**
* 过滤掉已经被授权的权限
*/
fun filter(permissions: Array): ArrayList {
var pers = ArrayList()
permissions.forEach { s ->
if (activity?.checkSelfPermission(s) != PackageManager.PERMISSION_GRANTED) pers.add(s)
}
return pers
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
hadlePermissionCallBack(requestCode, grantResults)
handleEachPermission(requestCode, permissions, grantResults);
}
}
这里我特别处理了版本低于6.0时的情况和当一些权限被禁掉且不再询问的时候弹出自定义的dialog来询问用户是否要跳到设置页面打开权限,已经被授权的权限就会被过滤掉
/**
* 过滤掉已经被授权的权限
*/
fun filter(permissions: Array): ArrayList {
var pers = ArrayList()
permissions.forEach { s ->
if (activity?.checkSelfPermission(s) != PackageManager.PERMISSION_GRANTED) pers.add(s)
}
return pers
}
/*
* 弹出打开被禁掉且不再询问的权限的对话框
* */
private fun showOpenPermissionSettingDialog(permission: Array) {
SettingDialog.getInstance().setContent("需要打开${PermissionToChinese.toChinese(permission[0])}权限才可以使用该功能").setOnClickListener(object : SettingDialog.OnClickListener {
override fun onPositive() {
jumbToPermissionSetting()
}
}).show(activity!!.supportFragmentManager, "SettingDialog")
}
最后用一个帮助类来包裹下,是调用者不知道内部是使用的fragment来申请的权限
object PermissionHelper {
val FRAGMENT_TAG = "PermissionFragment"
/**
* 一次性请求权限
*/
@JvmStatic
fun requestPermissions(pers: Array, callback: PermissiomCallBack.CallBack) {
val fragmentManage = (AppManager.instance.getTopActivity() as AppCompatActivity).supportFragmentManager
var fragment = fragmentManage.findFragmentByTag(FRAGMENT_TAG)
if (fragment == null) {
fragment = PermissionFragment()
fragmentManage.beginTransaction().add(fragment, FRAGMENT_TAG).commit()
fragmentManage.executePendingTransactions()
}
fragment as PermissionFragment
fragment.requestPermissons(pers, callback)
}
/**
* 别分返回每个权限的请求结果
*/
@JvmStatic
fun requestEachPermissions(permissions: Array, callback: PermissiomCallBack.EachCallBack) {
val fragmentManage = (AppManager.instance.getTopActivity() as AppCompatActivity).supportFragmentManager
var fragment = fragmentManage.findFragmentByTag(FRAGMENT_TAG)
if (fragment == null) {
fragment = PermissionFragment()
fragmentManage.beginTransaction().add(fragment, FRAGMENT_TAG).commit()
fragmentManage.executePendingTransactions()
}
fragment as PermissionFragment
fragment.requestEachPermission(permissions, callback)
}
}
最后就是调用了,很简单
PermissionHelper.requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.CALL_PHONE}, new PermissiomCallBack.CallBack() {
@Override
public void onGranded() {
}
@Override
public void onDenied() {
}
});
});
或者使用每个权限申请各自的回调结果来判断,就是有多少个权限,就会回调多少次 onResult方法,当然如果传入的权限中有一些是已经被授权的了,就会被过滤掉了
PermissionHelper.requestEachPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.CALL_PHONE}, new PermissiomCallBack.EachCallBack() {
@Override
public void onResult(@NotNull Permission permission) {
}
});
这里的onResult方法中的permission其实就两个成员变量
class Permission {
var name = ""
var isGranded = false
constructor(name: String, isGranded: Boolean) {
this.name = name
this.isGranded = isGranded
}
constructor()
}
name -> 权限的名字
isGranded -> 权限是否被授权
顺便贴下其他几个类的代码吧
class SettingDialog : DialogFragment() {
var onClickListener: OnClickListener? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.dialog_setting, container, false)
view.findViewById(R.id.tv_cancel).setOnClickListener {
with(onClickListener) {
this?.onCancel()
}
dismiss()
}
view.findViewById(R.id.tv_positive).setOnClickListener {
with(onClickListener) {
this?.onPositive()
}
dismiss()
}
view.findViewById(R.id.tv_content).text = arguments?.getString("content")
return view
}
fun setContent(conetent: String): SettingDialog {
val bundle = Bundle()
bundle.putString("content", conetent)
arguments = bundle
return this
}
fun setOnClickListener(onClickListener: OnClickListener?): SettingDialog {
this.onClickListener = onClickListener
return this
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
var dialog = super.onCreateDialog(savedInstanceState)
dialog.window.setBackgroundDrawableResource(R.drawable.bg_round4)
return dialog
}
fun show() {
show(activity?.supportFragmentManager, "SettingDialog")
}
companion object {
fun getInstance() = SettingDialog()
}
interface OnClickListener {
fun onPositive()
fun onCancel() {
}
}
}
object PermissionToChinese {
@JvmStatic
fun toChinese(permission:String):String{
var str=""
when(permission){
"android.permission.ACCESS_FINE_LOCATION" ->{str="位置"}
"android.permission.CAMERA" ->{str="相机"}
"android.permission.WRITE_EXTERNAL_STORAGE" ->{str="存储"}
"android.permission.READ_EXTERNAL_STORAGE" ->{str="存储"}
"android.permission.READ_PHONE_STATE" ->{str="电话"}
"android.permission.ACCESS_NETWORK_STATE" ->{str="位置"}
"android.permission.ACCESS_WIFI_STATE" ->{str="wify"}
else -> str= "部分"
}
return str
}
}
/**
* Created by alan on 2019/4/4 17:40
*/
interface PermissiomCallBack {
interface CallBack {
fun onGranded()
fun onDenied()
}
interface EachCallBack {
fun onResult(permission: Permission)
}
}
class AppManager {
fun getActivityStack(): Stack? {
return activityStack
}
private var activityStack: Stack? = null
private constructor()
companion object {
val instance by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { AppManager() }
}
/* */
/**
* 单一实例
*//*
fun getInstance(): AppManager {
if (instance == null) {
instance = AppManager()
}
return instance as AppManager
}*/
/**
* 添加Activity到堆栈
*/
fun addActivity(activity: Activity) {
if (activityStack == null) {
activityStack = Stack()
}
activityStack!!.add(activity)
}
/**
* 获取栈顶Activity(堆栈中最后一个压入的)
*/
fun getTopActivity(): Activity {
return activityStack!!.lastElement()
}
/**
* 结束栈顶Activity(堆栈中最后一个压入的)
*/
fun finishTopActivity() {
val activity = activityStack!!.lastElement()
finishActivity(activity)
}
/**
* 结束指定类名的Activity
*
* @param cls
*/
fun finishActivity(cls: Class<*>) {
val iterator = activityStack!!.iterator()
while (iterator.hasNext()) {
val activity = iterator.next() as Activity
if (activity.javaClass == cls) {
iterator.remove()
activity.finish()
}
}
}
/**
* 结束所有Activity
*/
fun finishAllActivity() {
var i = 0
val size = activityStack!!.size
while (i < size) {
if (null != activityStack!!.get(i)) {
activityStack!!.get(i).finish()
}
i++
}
activityStack!!.clear()
}
/**
* 退出应用程序
*/
fun appExit() {
try {
finishAllActivity()
System.exit(0)
android.os.Process.killProcess(android.os.Process.myPid())
} catch (e: Exception) {
}
}
/**
* 结束指定的Activity
*/
fun finishActivity(activity: Activity?) {
var activity = activity
if (activity != null) {
activityStack!!.remove(activity)
activity.finish()
activity = null
}
}
/**
* 得到指定类名的Activity
*/
fun getActivity(cls: Class<*>): Activity? {
for (activity in activityStack!!) {
if (activity.javaClass == cls) {
return activity
}
}
return null
}
}
ok,代码总体还是挺简单的,就是如果没有了解多kotlin的同学就会看得比较迷茫了,这里也给出代码的地址,想了解的可以去看下传送门