2018-05-07

【Android Studio】執行時期為 APP 取得權限(授權)

參考資料 ----
Request App Permissions


在執行時期取得權限,是自 Marshmallow(6.0, API23) 加入的功能,為使用者提供更多保護;回想一下,您在安裝 APP 時,會仔細看 APP 要求取得哪些權限嗎?自 Android6.0(含) 起,在 APP 第一次執行時,會提示使用者,您的 APP 需要取得哪些權限,並必須得使用者允許。

所以在 Android6.0(含) 以上的裝置,如果沒有撰寫相關的程式碼,為 APP 執行時期取得權限,嚴重時甚至 APPcrash 掉!

AndroidManifest.xml (宣告 APP 必須取得的權限)
 
<!-- 要求取得相機權限 -->
<uses-permission android:name="android.permission.CAMERA"/>

...
...

<application
        ...
        ...
 

編輯 build.gradle(Module: app)
 
dependencies {
    
    ...
    ...

    implementation 'com.android.support:design:27.1.1'      // Snackbar 需要
}
 


activity_main.xml (記得要給 layout ID,不然 Snackbar 不會顯示)
 
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="開啟相機"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:onClick="showCameraPreview"/>

</android.support.constraint.ConstraintLayout>
 

Mainactivity.java
 
public class MainActivity extends AppCompatActivity implements ActivityCompat.OnRequestPermissionsResultCallback
{
    private static final int PERMISSION_REQUEST_CAMERA = 0;
    private View mLayout;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mLayout = findViewById(R.id.main_layout);
    }

    public void showCameraPreview(View v)
    {
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED)
            {
                Snackbar.make(mLayout, "已取得相機權限, 開始預覽", Snackbar.LENGTH_SHORT).show();
                startCamera();
            }
        else
            {
                requestCameraPermission();
            }
    }

    private void startCamera()
    {
        // 開啟相機, 在此寫您自己的程式
    }

    private void requestCameraPermission()
    {
        if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA))
            {
                Snackbar.make(mLayout, "需要取得相機權限", Snackbar.LENGTH_INDEFINITE)
                        .setAction("OK", new View.OnClickListener()
                                            {
                                                @Override
                                                public void onClick(View view)
                                                {
                                                    ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.CAMERA}, PERMISSION_REQUEST_CAMERA);
                                                }
                                            })
                        .show();
            }
        else
            {
                Snackbar.make(mLayout, "無法開啟相機,可能有其他 APP 正在使用中 或 本 APP 尚未取得授權", Snackbar.LENGTH_SHORT).show();
                ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, PERMISSION_REQUEST_CAMERA);
            }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)
    {
        if (requestCode == PERMISSION_REQUEST_CAMERA)
        {
            if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED)
                {
                    Snackbar.make(mLayout, "已取得相機權限, 開始預覽", Snackbar.LENGTH_SHORT)
                            .show();
                    startCamera();
                }
            else
                {
                    Snackbar.make(mLayout, "請求相機權限被拒", Snackbar.LENGTH_SHORT)
                            .show();
                }
        }
    }
}
 


APP 安裝到實體裝置後,先關閉不執行,到 Android 的 "設定" 進一步觀察:

安裝在 KitKat4.4(API19),就已經取得權限



安裝在 Oreo8.0(API26),尚未取得權限



執行 APP,點擊 "開啟相機" 鈕,會出現請求授權的畫面



選取 "拒絕",就會跳出 "請求相機權限被拒" 的 Snackbar



再按一次 "開啟相機",這次 Snackbar 會提示您 APP 需要取得相機權限,選取 "OK"



打勾 "不要再詢問",並再次拒絕



這麼一來,就再也不會出現請求授權的畫面了,只能到 "設定" → 應用程式與通知應用程式資訊 → 找到 APP → 點擊 "權限" 去手動開啟授權

或是將 APP 移除再重新安裝了



若是在 請求授權畫面選擇 "允許" 或 手動進 "設定" 開啟授權 後,執行 APP 點擊 "開啟相機" 鈕,就會跳出已取得授權的 Snackbar




相關筆記 ----
Snackbar -- 比 Toast 更多功能的 跳出式訊息