1. 程式人生 > >Android 權限處理

Android 權限處理

沙盒 thread 缺點 appcompat 用戶體驗 val com PC mission

概述:

為了保護系統的完整性和用戶隱私權,Android 在訪問受限的沙盒中運行每款應用。

如果應用需要使用其沙盒以外的資源或信息,則必須明確請求權限。

根據應用請求的權限類型,系統可能會自動授予權限,也可能會要求用戶授予權限。

權限最佳做法:

1.考慮使用intent 例子:MainActivity@ this.startActivityForResult(takeIntent, 1) -- 這個優先,使用簡單方便

2.如果使用權限

  1. 僅要求您需要的權限,不要要求太多;
  2. 在需要的地方申請權限,而不是一次性申請;
  3. 解釋需要權限的原因不要冗長;
  4. 拒絕權限需要有對應提示。

優缺點:

如果使用權限:

您的應用可在您執行操作時完全控制用戶體驗。不過,如此廣泛的控制會增加任務的復雜性,因為您需要設計適當的 UI。

系統會在運行或安裝應用時各提示用戶提供一次權限(具體取決於用戶的 Android 版本)。之後,應用即可執行操作,不再需要用戶進行其他交互。不過,如果用戶不授予權限(或稍後撤銷權限),您的應用將根本無法執行操作。

如果使用 intent:

您無需為操作設計 UI。處理 intent 的應用將提供 UI。不過,這意味著您無法控制用戶體驗。用戶可能與您從未見過的應用交互。

如果用戶沒有適用於操作的默認應用,則系統會提示用戶選擇一款應用。如果用戶未指定默認處理程序,則他們每次執行此操作時都必須處理一個額外對話框。


使用權限做法:

1.在應用清單中聲明需要的權限。

  1.1 在所有版本的 Android 中,您的應用都需要在其應用清單中同時聲明它需要的正常權限和危險權限。

2.運行時請求用戶授予權限。僅適用於運行 Android 6.0(API 級別 23)及更高版本的設備上的應用。

  2.1 系統在您聲明權限之後的行為取決於權限的敏感性。如果權限不影響用戶隱私權,系統會自動授權。

    如果權限可能涉及對敏感用戶信息的訪問,系統將要求用戶審批請求。

    要了解有關不同種類權限的詳細信息,請參閱正常權限和危險權限。

  2.2 使用 Android 支持庫來檢查和請求權限。Android 框架從 Android 6.0(API 級別 23)開始提供類似方法。

    不過,使用支持庫更簡單,因為在調用方法前,您的應用不需要檢查它在哪個版本的 Android 上運行。

    (appcompat 庫,通常情況下,名稱以 …Compat(如 ActivityCompat)結束的類即是如此。)

2.3 要檢查您是否具有某項權限,請調用 ContextCompat.checkSelfPermission() 方法。

  例如,以下代碼段顯示了如何檢查 Activity 是否具有在日歷中進行寫入的權限:

  // Assume thisActivity is the current activity

  int permissionCheck = ContextCompat.checkSelfPermission(thisActivity,Manifest.permission.WRITE_CALENDAR);

  如果應用具有此權限,方法將返回 PackageManager.PERMISSION_GRANTED,並且應用可以繼續操作。如果應用不具有此權限,方法將返回 PERMISSION_DENIED,且應用必須明確向用戶要求權限。

package pers.hbolin.permissionsdemo

import android.Manifest
import android.app.Activity
import android.content.pm.PackageManager
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.support.v4.app.ActivityCompat
import android.support.v4.content.ContextCompat
import android.support.v7.app.AlertDialog
import android.util.Log
import kotlinx.android.synthetic.main.activity_main.*
import android.provider.MediaStore
import android.content.Intent
import android.graphics.Bitmap


class MainActivity : AppCompatActivity() {
    val TAG = "MainActivity"

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        callReadContacts()

        button.setOnClickListener {
            // 使用Intent,可以不用在AndroidManifest.xml中配置權限
            // 也不需要動態配置權限,即可調用
            // 這裏缺少判斷,是否有東西響應這個Intent,不然會拋出異常的。
            val takeIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
            MainActivity@ this.startActivityForResult(takeIntent, 1)
        }
    }

    // 請求權限
    private fun callReadContacts() {
        // Here, thisActivity is the current activity
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {

            Log.d(TAG, "未獲取到權限")

            // Should we show an explanation?
            if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_CONTACTS)) {

                // Show an expanation to the user *asynchronously* -- don‘t block
                // this thread waiting for the user‘s response! After the user
                // sees the explanation, try again to request the permission.

                Log.d(TAG, "解釋為什麽需要權限")

                val builder = AlertDialog.Builder(this)
                builder.setTitle("解釋為什麽需要權限")
                        .setMessage("因為是在測試")
                        .setPositiveButton("確定") { _, _ ->
                            // 申請權限
                            ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_CONTACTS), 1)
                        }
                        .setNegativeButton("取消") { _, _ -> }
                        .create().show()
            } else {

                // No explanation needed, we can request the permission.

                ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_CONTACTS), 1)

                // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
                // app-defined int constant. The callback method gets the
                // result of the request.
            }
        } else {
            Log.d(TAG, "已獲取到權限")
        }
    }

    // 請求回調
    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {

        if (requestCode == 1) {
            if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                Log.d(TAG, "權限同意")
            } else {
                Log.d(TAG, "權限禁止")
            }
        }

    }

    // startActivityForResult 回調
    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        Log.d(TAG, "請求 $requestCode and 結果 $resultCode and data is null :${data == null}")
        if (requestCode == 1 && resultCode == Activity.RESULT_OK) {
            if (data?.hasExtra("data") == true) {
                Log.i(TAG, "data is not null")
                val bitmap = data.getParcelableExtra<Bitmap>("data")
                Log.d(TAG, "bitmap.width is ${bitmap.width}")
                imageView.setImageBitmap(bitmap) //imageView即為當前頁面需要展示照片的控件,可替換
            }
        }
    }
}

Android 權限處理