JPermissions权限请求框架

6.0以上动态权限

将系统权限区分为正常权限和危险权限。开发者在使用到危险权限相关的功能时,不仅需要在Manifest文件中配置,还需要在代码中动态获取权限

需要注意的几个权限

  • 6.0以上需要检测悬浮窗权限
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

 /**
     * 是否有悬浮窗权限
     */
    static boolean isHasOverlaysPermission(Context context) {
        if (isOverMarshmallow()) {
            return Settings.canDrawOverlays(context);
        }
        return true;
    }

/**
     * 用于6.0悬浮窗权限请求
     */
 // 跳转到允许安装未知来源设置页面
 Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, Uri.parse("package:" + getActivity().getPackageName()));
 startActivityForResult(intent, getArguments().getInt(REQUEST_CODE));
  • 8.0以上需要检测以下权限
//未知应用安装权限
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>

 /**
     * 是否有安装权限
     */
    static boolean isHasInstallPermission(Context context) {
        if (isOverOreo()) {
            return context.getPackageManager().canRequestPackageInstalls();
        }
        return true;
    }
/**
     * 用于8.0安装第三方应用权限请求
     */
// 跳转到悬浮窗设置页面
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getActivity().getPackageName()));
startActivityForResult(intent, getArguments().getInt(REQUEST_CODE));

//允许您的应用通过编程方式接听呼入电话。要在您的应用中处理呼入电话,您可以使用 acceptRingingCall() 函数。 
ANSWER_PHONE_CALLS 
//允许您的应用读取设备中存储的电话号码。 
READ_PHONE_NUMBERS 

代码

/**
 * justin
 * 危险权限请求类
 */
class JPermissions {
    private var mActivity:Activity
    private var mPermissions:MutableList<String> = ArrayList()
    private var mRequestAgain: Boolean = false

    private constructor(activity:Activity){
        mActivity = activity
    }

    companion object {
        /**
         * 设置请求的对象
         */
        fun with(activity: Activity): JPermissions {
            return JPermissions(activity)
        }

        /**
         * 检查某些权限是否全部授予了
         *
         * @param context     上下文对象
         * @param permissions 需要请求的权限组
         */
        fun isHasPermission(context: Context, vararg permissions: String): Boolean {
            val failPermissions = PermissionUtils.getDeniedPermissions(context, Arrays.asList(*permissions))
            return failPermissions == null || failPermissions.isEmpty()
        }

        /**
         * 跳转到应用权限设置页面
         *
         * @param context 上下文对象
         */
        fun gotoPermissionSettings(context: Context) {
            PermissionSettingPage.start(context, false)
        }

        /**
         * 跳转到应用权限设置页面
         *
         * @param context 上下文对象
         * @param newTask 是否使用新的任务栈启动
         */
        fun gotoPermissionSettings(context: Context, newTask: Boolean) {
            PermissionSettingPage.start(context, newTask)
        }

    }

    /**
     * 设置需要请求的权限
     */
    fun permissions(vararg permissions: String):JPermissions{
        mPermissions.addAll(permissions)
        return this
    }

    /**
     * 被拒绝后继续申请,直到授权或者永久拒绝
     */
    fun requestAgain(): JPermissions {
        mRequestAgain = true
        return this
    }

    /**
     * 请求权限
     */
    fun requestPermissions(permissionResult:OnPermissionsResult) {
        // 如果没有指定请求的权限,就使用清单注册的权限进行请求
        if (mPermissions.isEmpty()) mPermissions = PermissionUtils.getManifestPermissions(mActivity)
        if (mPermissions.isEmpty()) throw IllegalArgumentException("The requested permission cannot be empty")
        if (mActivity == null) throw IllegalArgumentException("The activity is empty")
        if (permissionResult == null) throw IllegalArgumentException("The permission request callback interface must be implemented")
        val checkTargetSdkVersion = PermissionUtils.checkTargetSdkVersion(mActivity,mPermissions)
        if (!checkTargetSdkVersion) return
        val deniedPermissions = PermissionUtils.getDeniedPermissions(mActivity, mPermissions)
        //权限已经全部授予
        if (deniedPermissions.isEmpty()){
            permissionResult.agreePermission(mPermissions,true)
        }else{
            // 检测权限有没有在清单文件中注册
            PermissionUtils.checkPermissionsIsInManifest(mActivity, mPermissions)
            // 申请没有授予过的权限
            PermissionFragment.newInstance(ArrayList(mPermissions), mRequestAgain).prepareRequest(mActivity, permissionResult)
        }

    }

}
/**
 *   author:justin
 *   time:2019/04/22
 *   desc:权限请求处理类
 */
class PermissionFragment : Fragment, Runnable {
    
    constructor() : super()
    companion object {
        private val PERMISSIONS: String = "permissions" // 请求的权限
        private val REQUEST_CODE: String = "request_code" // 请求码(自动生成)
        private val REQUEST_AGAIN: String = "request_again" // 是否不断请求
        private val sContainer: SparseArray<OnPermissionsResult> = SparseArray()

        fun newInstance(permissions: ArrayList<String>, requestAgain: Boolean): PermissionFragment {
            val fragment = PermissionFragment()
            val bundle = Bundle()
            var requestCode: Int
            // 请求码随机生成,避免随机产生之前的请求码,必须进行循环判断
            do {
                // requestCode = new Random().nextInt(65535); // Studio编译的APK请求码必须小于65536
                requestCode = Random().nextInt(255) // Eclipse编译的APK请求码必须小于256
            } while (sContainer.get(requestCode) != null)
            bundle.putInt(REQUEST_CODE, requestCode)
            bundle.putStringArrayList(PERMISSIONS, permissions)
            bundle.putBoolean(REQUEST_AGAIN, requestAgain)
            fragment.arguments = bundle
            return fragment
        }
    }

    /**
     * 用于6.0悬浮窗 8.0安装第三方应用权限请求
     */
    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        val permissions = arguments!!.getStringArrayList(PERMISSIONS)
        if (permissions == null || permissions.isEmpty()) return
        if (permissions.contains(Manifest.permission.SYSTEM_ALERT_WINDOW) && !PermissionUtils.isHasOverlaysPermission(getActivity())
                ||permissions.contains(Manifest.permission.REQUEST_INSTALL_PACKAGES) && !PermissionUtils.isHasInstallPermission(getActivity())) {
            if (permissions.contains(Manifest.permission.SYSTEM_ALERT_WINDOW) && !PermissionUtils.isHasOverlaysPermission(getActivity())) {
                // 跳转到悬浮窗设置页面
                val intent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + activity!!.getPackageName()))
                startActivityForResult(intent, arguments!!.getInt(REQUEST_CODE))
            }

            if (permissions.contains(Manifest.permission.REQUEST_INSTALL_PACKAGES) && !PermissionUtils.isHasInstallPermission(getActivity())) {
                // 跳转到允许安装未知来源设置页面
                val intent = Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, Uri.parse("package:" + activity!!.getPackageName()))
                startActivityForResult(intent, arguments!!.getInt(REQUEST_CODE))
            }
            return
        }

        requestPermission()
    }

    /**
     * 准备请求
     */
    fun prepareRequest(activity: Activity, call: OnPermissionsResult) {
        // 将当前的请求码和对象添加到集合中
        sContainer.put(arguments!!.getInt(REQUEST_CODE), call)
        activity.fragmentManager.beginTransaction().add(this, activity.javaClass.name).commit()
    }

    /**
     * 请求权限
     */
    fun requestPermission() {
        if (PermissionUtils.isOverMarshmallow()) {
            val permissions = arguments!!.getStringArrayList(PERMISSIONS)
            requestPermissions(permissions!!.toTypedArray(), arguments!!.getInt(REQUEST_CODE))
        }
    }

    /**
     * 权限请求结果回调(除过6.0悬浮窗 8.0安装第三方应用回调)
     */
    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
        val onPermissionsResult = sContainer.get(requestCode)
        if (onPermissionsResult == null) return
        for (i in permissions.indices) {
            // 重新检查悬浮窗权限
            if (Permission.SYSTEM_ALERT_WINDOW == permissions[i]) {
                if (PermissionUtils.isHasOverlaysPermission(activity)) {
                    grantResults[i] = PackageManager.PERMISSION_GRANTED
                } else {
                    grantResults[i] = PackageManager.PERMISSION_DENIED
                }
            }
            // 重新检查安装权限
            if (Permission.REQUEST_INSTALL_PACKAGES == permissions[i]) {
                if (PermissionUtils.isHasInstallPermission(activity)) {
                    grantResults[i] = PackageManager.PERMISSION_GRANTED
                } else {
                    grantResults[i] = PackageManager.PERMISSION_DENIED
                }
            }

            // 重新检查8.0的两个新权限
            if (permissions[i] == Permission.ANSWER_PHONE_CALLS || permissions[i] == Permission.READ_PHONE_NUMBERS) {

                // 检查当前的安卓版本是否符合要求
                if (!PermissionUtils.isOverOreo()) {
                    grantResults[i] = PackageManager.PERMISSION_GRANTED
                }
            }
        }

        val deniedPermissions = PermissionUtils.getDeniedPermissions(activity as Context, permissions.asList())
        if (deniedPermissions.isEmpty()) {
            onPermissionsResult.agreePermission(permissions.toList(), true)
        } else {
            // 检查是否开启了继续申请模式,如果是则检查没有授予的权限是否还能继续申请
            if (arguments!!.getBoolean(REQUEST_AGAIN) && PermissionUtils.isRequestDeniedPermission(activity as Activity, deniedPermissions)) {

                // 如果有的话就继续申请权限,直到用户授权或者永久拒绝
                requestPermission()
                return
            }

            // 代表申请的权限中有不同意授予的,如果有某个权限被永久拒绝就返回true给开发人员,让开发者引导用户去设置界面开启权限
            onPermissionsResult.disagreePermission(deniedPermissions, PermissionUtils.checkMorePermissionPermanentDenied(activity as Activity, deniedPermissions))

            // 证明还有一部分权限被成功授予,回调成功接口
            if (permissions.size>deniedPermissions.size){
                val succeePermissions = permissions.toMutableList()
                val succeed = succeePermissions.removeAll(deniedPermissions)
                if (succeed) {
                    if (!succeePermissions.isEmpty()) {
                        onPermissionsResult.agreePermission(succeePermissions, false)
                    }
                }
            }

        }
        // 权限回调结束后要删除集合中的对象,避免重复请求
        sContainer.remove(requestCode)
        fragmentManager!!.beginTransaction().remove(this).commit()
    }

    private var isBackCall: Boolean = false // 是否已经回调了,避免安装权限和悬浮窗同时请求导致的重复回调

    /**
     * 6.0悬浮窗 8.0安装第三方应用回调
     * 需要注意第三个Intent参数,kotlin的NULL检查机制,导致不写?一直回调不成功(坑)
     */
    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
//         super.onActivityResult(requestCode, resultCode, data);
        if (!isBackCall && requestCode == arguments!!.getInt(REQUEST_CODE)) {
            isBackCall = true
            // 需要延迟执行,不然有些华为机型授权了但是获取不到权限
            Handler(Looper.getMainLooper()).postDelayed(this, 500)
        }
    }

    /**
     * [Runnable.run]
     */
    override fun run() {
        // 请求其他危险权限
        requestPermission()
    }

}

PermissionFragment通过名字也能看出,这里采用了Fragment来处理请求回调,Fragment的妙用有很多,比如解决自定义view绑定生命周期的问题(百度地图还需要用户自己去绑定生命周期,不友好啊...)

/**
 * 权限请求工具类
 */
class PermissionUtils {
    companion object {
        /**
         * 获取清单文件中的权限
         */
        fun getManifestPermissions(context: Context): MutableList<String> {
            return context.packageManager.getPackageInfo(context.packageName,
                    PackageManager.GET_PERMISSIONS).requestedPermissions.toMutableList()
        }

        /**
         * 检查targetSdkVersion是否符合要求
         *
         * @param context                   上下文对象
         * @param requestPermissions       请求的权限组
         */
        fun checkTargetSdkVersion(context: Context, requestPermissions: List<String>):Boolean {
            if (requestPermissions.contains(Manifest.permission.REQUEST_INSTALL_PACKAGES)
                    || requestPermissions.contains(Manifest.permission.ANSWER_PHONE_CALLS)
                    || requestPermissions.contains(Manifest.permission.READ_PHONE_NUMBERS)) {
                // 必须设置 targetSdkVersion >= 26 才能正常检测权限
                if (context.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.O) {
                    return true
                }
            }

            if (context.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.M) {
                return true
            }

            return false
        }

        /**
         * 获取未授权权限
         */
        fun getDeniedPermissions(context: Context, requestPermissions: List<String>):MutableList<String>{
            var deniedList:MutableList<String> = ArrayList()
            for (permission in requestPermissions) {
                //检测6.0悬浮窗权限
                if (TextUtils.equals(permission,Manifest.permission.SYSTEM_ALERT_WINDOW)){
                    if (!isHasOverlaysPermission(context)) {
                        deniedList.add(permission)
                        continue
                    }
                }
                //检测8.0以上安装未知来源应用权限
                if (TextUtils.equals(permission,Manifest.permission.REQUEST_INSTALL_PACKAGES)){
                    if (!isHasInstallPermission(context)){
                        deniedList.add(permission)
                        continue
                    }
                }
                //检测8.0的两个新权限
                if (TextUtils.equals(permission,Manifest.permission.ANSWER_PHONE_CALLS)
                        ||TextUtils.equals(permission,Manifest.permission.READ_PHONE_NUMBERS)){
                    if (!isOverOreo()){
                        continue
                    }
                }
                    // 把没有授予过的权限加入到集合中
                if (ActivityCompat.checkSelfPermission(context,permission) == PackageManager.PERMISSION_DENIED) {
                    deniedList.add(permission)
                }

            }
            return deniedList
        }

        /**
         * 检测6.0悬浮窗权限
         */
         fun isHasOverlaysPermission(context: Context): Boolean {
            if (isOverMarshmallow()){
                return Settings.canDrawOverlays(context)
            }
            return true
        }

        /**
         * 检测8.0以上安装未知来源应用权限
         */
         fun isHasInstallPermission(context: Context): Boolean {
            if (isOverOreo()){
                return context!!.packageManager.canRequestPackageInstalls()
            }
            return true
        }

        /**
         * 是否是6.0以上版本
         */
        fun isOverMarshmallow(): Boolean {
            return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
        }

        /**
         * 是否是8.0以上版本
         */
        fun isOverOreo(): Boolean {
            return Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
        }

        /**
         * 检测权限是否在清单文件中注册
         */
        fun checkPermissionsIsInManifest(context: Context,requestPermissions: List<String>){
            val manifestPermissions = getManifestPermissions(context)
            if (manifestPermissions != null&&!manifestPermissions.isEmpty()){
                for (permission in requestPermissions) {
                    if (!manifestPermissions.contains(permission)){
                        throw RuntimeException(permission + ": Permissions are not registered in the manifest file")
                    }
                }

            }else{
                throw RuntimeException("No permissions are registered in the manifest file")
            }
        }

        /**
         * 在权限组中检查是否有某个权限是否被永久拒绝
         *
         * @param activity              Activity对象
         * @param permissions            请求的权限
         */
        fun checkMorePermissionPermanentDenied(activity: Activity, permissions: List<String>): Boolean {
            for (permission in permissions) {
                // 安装权限和浮窗权限不算,本身申请方式和危险权限申请方式不同,因为没有永久拒绝的选项,所以这里返回false
                if (permission == Permission.REQUEST_INSTALL_PACKAGES || permission == Permission.SYSTEM_ALERT_WINDOW) {
                    continue
                }
                if (checkSinglePermissionPermanentDenied(activity, permission)) {
                    return true
                }
            }
            return false
        }

        /**
         * 检查某个权限是否被永久拒绝
         *
         * @param activity              Activity对象
         * @param permission            请求的权限
         */
        fun checkSinglePermissionPermanentDenied(activity: Activity, permission: String): Boolean {

            //        // 安装权限和浮窗权限不算,本身申请方式和危险权限申请方式不同,因为没有永久拒绝的选项,所以这里返回false
            //        if (permission.equals(Permission.REQUEST_INSTALL_PACKAGES) || permission.equals(Permission.SYSTEM_ALERT_WINDOW)) {
            //            return false;
            //        }

            // 检测8.0的两个新权限
            if (permission == Permission.ANSWER_PHONE_CALLS || permission == Permission.READ_PHONE_NUMBERS) {

                // 检查当前的安卓版本是否符合要求
                if (!isOverOreo()) {
                    return false
                }
            }

            if (PermissionUtils.isOverMarshmallow()) {
                if (activity.checkSelfPermission(permission) == PackageManager.PERMISSION_DENIED && !activity.shouldShowRequestPermissionRationale(permission)) {
                    return true
                }
            }
            return false
        }

        /**
         * 是否还能继续申请没有授予的权限
         *
         * @param activity              Activity对象
         * @param failPermissions       失败的权限
         */
        fun isRequestDeniedPermission(activity: Activity, failPermissions: List<String>): Boolean {
            for (permission in failPermissions) {
                // 安装权限和浮窗权限不算,本身申请方式和危险权限申请方式不同,因为没有永久拒绝的选项,所以这里返回false
                if (permission == Permission.REQUEST_INSTALL_PACKAGES || permission == Permission.SYSTEM_ALERT_WINDOW) {
                    continue
                }

                // 检查是否还有权限还能继续申请的(这里指没有被授予的权限但是也没有被永久拒绝的)
                if (!checkSinglePermissionPermanentDenied(activity, permission)) {
                    return true
                }
            }
            return false
        }

        /**
         * 获取已授予的权限
         *
         * @param permissions       需要请求的权限组
         * @param grantResults      允许结果组
         */
        fun getSucceedPermissions(permissions: Array<String>, grantResults: IntArray): List<String> {

            val succeedPermissions = java.util.ArrayList<String>()
            for (i in grantResults.indices) {

                // 把授予过的权限加入到集合中,-1表示没有授予,0表示已经授予
                if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
                    succeedPermissions.add(permissions[i])
                }
            }
            return succeedPermissions
        }
    }
}
/**
 *   author:justin
 *   time:2019/04/24
 *   desc: 权限设置页(兼容大部分国产手机)
 */

internal object PermissionSettingPage {
    /**
     * 手机制造商
     */
    private val MARK = Build.MANUFACTURER.toLowerCase()
    /**
     * 跳转到应用权限设置页面
     *
     * @param context 上下文对象
     * @param newTask 是否使用新的任务栈启动
     */
    fun start(context: Context, newTask: Boolean) {

        var intent: Intent? = null
        if (MARK.contains("huawei")) {
            intent = huawei(context)
        } else if (MARK.contains("xiaomi")) {
            intent = xiaomi(context)
        } else if (MARK.contains("oppo")) {
            intent = oppo(context)
        } else if (MARK.contains("vivo")) {
            intent = vivo(context)
        } else if (MARK.contains("meizu")) {
            intent = meizu(context)
        }

        if (intent == null || !hasIntent(context, intent)) {
            intent = google(context)
        }

        if (newTask) {
            //如果用户在权限设置页面改动了权限,个别手机请求权限的activity会被重启,解决该问题
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        }

        try {
            context.startActivity(intent)
        } catch (ignored: Exception) {
            intent = google(context)
            context.startActivity(intent)
        }

    }

    private fun google(context: Context): Intent {
        val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
        intent.data = Uri.fromParts("package", context.packageName, null)
        return intent
    }

    private fun huawei(context: Context): Intent {
        val intent = Intent()
        intent.component = ComponentName("com.huawei.systemmanager", "com.huawei.permissionmanager.ui.MainActivity")
        if (hasIntent(context, intent)) return intent
        intent.component = ComponentName("com.huawei.systemmanager", "com.huawei.systemmanager.addviewmonitor.AddViewMonitorActivity")
        if (hasIntent(context, intent)) return intent
        intent.component = ComponentName("com.huawei.systemmanager", "com.huawei.notificationmanager.ui.NotificationManagmentActivity")
        return intent
    }

    private fun xiaomi(context: Context): Intent {
        val intent = Intent("miui.intent.action.APP_PERM_EDITOR")
        intent.putExtra("extra_pkgname", context.packageName)
        if (hasIntent(context, intent)) return intent

        intent.setPackage("com.miui.securitycenter")
        if (hasIntent(context, intent)) return intent

        intent.setClassName("com.miui.securitycenter", "com.miui.permcenter.permissions.AppPermissionsEditorActivity")
        if (hasIntent(context, intent)) return intent

        intent.setClassName("com.miui.securitycenter", "com.miui.permcenter.permissions.PermissionsEditorActivity")
        return intent
    }

    private fun oppo(context: Context): Intent {
        val intent = Intent()
        intent.putExtra("packageName", context.packageName)
        intent.setClassName("com.color.safecenter", "com.color.safecenter.permission.floatwindow.FloatWindowListActivity")
        if (hasIntent(context, intent)) return intent

        intent.setClassName("com.coloros.safecenter", "com.coloros.safecenter.sysfloatwindow.FloatWindowListActivity")
        if (hasIntent(context, intent)) return intent

        intent.setClassName("com.oppo.safe", "com.oppo.safe.permission.PermissionAppListActivity")
        return intent
    }

    private fun vivo(context: Context): Intent {
        val intent = Intent()
        intent.setClassName("com.iqoo.secure", "com.iqoo.secure.ui.phoneoptimize.FloatWindowManager")
        intent.putExtra("packagename", context.packageName)
        if (hasIntent(context, intent)) return intent

        intent.component = ComponentName("com.iqoo.secure", "com.iqoo.secure.safeguard.SoftPermissionDetailActivity")
        return intent
    }

    private fun meizu(context: Context): Intent {
        val intent = Intent("com.meizu.safe.security.SHOW_APPSEC")
        intent.putExtra("packageName", context.packageName)
        intent.component = ComponentName("com.meizu.safe", "com.meizu.safe.security.AppSecActivity")
        return intent
    }

    private fun hasIntent(context: Context, intent: Intent): Boolean {
        return !context.packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY).isEmpty()
    }
}
/**
 * 权限请求结果回调接口
 */
interface OnPermissionsResult {

    fun agreePermission(granted:List<String> , agreeAll:Boolean )

    fun disagreePermission(disagree:List<String> , never:Boolean )
}

使用

 JPermissions.with(this)
                .permissions(Manifest.permission.CAMERA,Manifest.permission.CALL_PHONE)//如果不设置,自动获取manifest文件下权限
                .requestAgain()//拒绝后再次请求,直到用户永久拒绝
                .requestPermissions(object :OnPermissionsResult{
                    override fun agreePermission(granted: List<String>, agreeAll: Boolean) {
                       if (agreeAll){
                           //获取所有权限成功
                           Toast.makeText(this@MainActivity,"全部请求成功",Toast.LENGTH_LONG).show()
                       }else{
                           //获取部分权限成功

                           Toast.makeText(this@MainActivity,granted.toString()+"部分请求成功",Toast.LENGTH_LONG).show()
                       }
                    }

                    override fun disagreePermission(disagree: List<String>, never: Boolean) {
                        if (never){
                          
                            Toast.makeText(this@MainActivity,disagree.toString()+"永久拒绝",Toast.LENGTH_LONG).show()
                            //被永久拒绝就跳转到应用权限系统设置页面
                            JPermissions.gotoPermissionSettings(this@MainActivity)
                        }else{
                            //获取权限失败
                            Toast.makeText(this@MainActivity,disagree.toString()+"获取失败",Toast.LENGTH_LONG).show()
                        }
                    }

                })
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,558评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,002评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,024评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,144评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,255评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,295评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,068评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,478评论 1 305
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,789评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,965评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,649评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,267评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,982评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,800评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,847评论 2 351

推荐阅读更多精彩内容