Android之運行時相機權限和聯繫人權限獲取

原文: Android之運行時相機權限和聯繫人權限獲取

本文連接:http://blog.csdn.net/qq_16628781/article/details/61623502css


Android之運行時相機權限和聯繫人權限獲取(最後又源碼能夠下載下來看)html


知識點:java

一、Android M 及以上系統的動態權限申請;android

二、知識名詞記錄git

{github

CameraPreview:自定義相機預覽類app

ViewAnimator:配合framelayout使用,在兩個view之間切換時,會有切換動畫ide

ContactsContract:佈局

CursorLoader:動畫

ContentProviderOperation:插入聯繫人用

讀取聯繫人列表;

}(這裏我決定,每篇文章中遇到的「新名詞」我都會記錄在這裏,做爲本身下一步須要瞭解的知識;你們有興趣的話,也能夠循着這些新的專業名詞,一步一步的走向Android更深的「泥潭」)


若是你有持續關注Android官方最新的SDK版本的話,你就會知道,Android官方對權限的管理變得原來越嚴格了。在5.0以後,權限再也不是所有都在manifest文件裏頭申請就OK了,你APP要的權限,當用到的時候,系統纔會賦予給你。


固然,你能夠這樣作,可是要把你的targetSdkVersion 變爲22如下,這樣是能夠暫時避免動態申請權限引發的「麻煩事」,可是這是一個不可逆的趨勢,咱們必需要順從它,而不是抗拒它,何況緊靠幾我的幾個應用,那是螳臂當車。


權限分爲:普通權限,危險權限和系統權限;

普通權限:這些權限對於用戶隱私和設備操做不會形成太多危險,主要有:

ACCESS_LOCATION_EXTRA_COMMANDS
ACCESS_NETWORK_STATE
ACCESS_NOTIFICATION_POLICY
ACCESS_WIFI_STATE
BLUETOOTH
BLUETOOTH_ADMIN
BROADCAST_STICKY
CHANGE_NETWORK_STATE
CHANGE_WIFI_MULTICAST_STATE
CHANGE_WIFI_STATE
DISABLE_KEYGUARD
EXPAND_STATUS_BAR
GET_PACKAGE_SIZE
INSTALL_SHORTCUT
INTERNET
KILL_BACKGROUND_PROCESSES
MODIFY_AUDIO_SETTINGS
NFC
READ_SYNC_SETTINGS
READ_SYNC_STATS
RECEIVE_BOOT_COMPLETED
REORDER_TASKS
REQUEST_INSTALL_PACKAGES
SET_ALARM
SET_TIME_ZONE
SET_WALLPAPER
SET_WALLPAPER_HINTS
TRANSMIT_IR
UNINSTALL_SHORTCUT
USE_FINGERPRINT
VIBRATE
WAKE_LOCK
WRITE_SYNC_SETTINGS


危險權限,主要是包含產生費用或者是讀取用戶隱私的權限,包含:

group:android.permission-group.CONTACTS
  permission:android.permission.WRITE_CONTACTS
  permission:android.permission.GET_ACCOUNTS
  permission:android.permission.READ_CONTACTS

group:android.permission-group.PHONE
  permission:android.permission.READ_CALL_LOG
  permission:android.permission.READ_PHONE_STATE
  permission:android.permission.CALL_PHONE
  permission:android.permission.WRITE_CALL_LOG
  permission:android.permission.USE_SIP
  permission:android.permission.PROCESS_OUTGOING_CALLS
  permission:com.android.voicemail.permission.ADD_VOICEMAIL

group:android.permission-group.CALENDAR
  permission:android.permission.READ_CALENDAR
  permission:android.permission.WRITE_CALENDAR

group:android.permission-group.CAMERA
  permission:android.permission.CAMERA

group:android.permission-group.SENSORS
  permission:android.permission.BODY_SENSORS

group:android.permission-group.LOCATION
  permission:android.permission.ACCESS_FINE_LOCATION
  permission:android.permission.ACCESS_COARSE_LOCATION

group:android.permission-group.STORAGE
  permission:android.permission.READ_EXTERNAL_STORAGE
  permission:android.permission.WRITE_EXTERNAL_STORAGE

group:android.permission-group.MICROPHONE
  permission:android.permission.RECORD_AUDIO

group:android.permission-group.SMS
  permission:android.permission.READ_SMS
  permission:android.permission.RECEIVE_WAP_PUSH
  permission:android.permission.RECEIVE_MMS
  permission:android.permission.RECEIVE_SMS
  permission:android.permission.SEND_SMS
  permission:android.permission.READ_CELL_BROADCASTS


上圖:


下面我這裏利用請求相機和聯繫人權限來演示一下在Android M 系統上的權限請求;我在這裏作了兩個fragment頁面,分別是相機和聯繫人相關的動做。

這裏我就只是貼一個主要的頁面代碼就行了,我這裏只是要一個觸發相機和聯繫人的動做就行了,代碼裏頭都有說明。

import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.Snackbar;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.FragmentTransaction;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ViewAnimator;

import com.example.android.common.logger.Log;
import com.example.android.common.logger.LogFragment;
import com.example.android.common.logger.LogWrapper;
import com.example.android.common.logger.MessageOnlyLogFilter;
import com.example.android.system.runtimepermissions.camera.CameraPreviewFragment;
import com.example.android.system.runtimepermissions.contacts.ContactsFragment;

import common.activities.SampleActivityBase;

public class MainActivity extends SampleActivityBase
        implements ActivityCompat.OnRequestPermissionsResultCallback {

    public static final String TAG = "MainActivity";

    /* 相機請求碼 */
    private static final int REQUEST_CAMERA = 0;

    /* 聯繫人請求碼 */
    private static final int REQUEST_CONTACTS = 1;

    /* 請求讀取聯繫人權限 */
    private static String[] PERMISSIONS_CONTACT = {Manifest.permission.READ_CONTACTS,
            Manifest.permission.WRITE_CONTACTS};

    // 標誌log fragment是否顯示
    private boolean mLogShown;

    /* 主頁的佈局,依靠動態加載進來 */
    private View mLayout;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mLayout = findViewById(R.id.sample_main_layout);

        if (savedInstanceState == null) {
            FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
            RuntimePermissionsFragment fragment = new RuntimePermissionsFragment();
            transaction.replace(R.id.sample_content_fragment, fragment);
            transaction.commit();
        }
        initializeLogging();
    }

    /**
     * 點擊顯示聯繫人按鈕相應
     * <p>
     * 回調已經被定義好了
     */
    public void showCamera(View view) {
        Log.i(TAG, "檢查權限是否被受理!");
        // 檢查是否想要的權限申請是否彈框。若是是第一次申請,用戶不經過,
        // 那麼第二次申請的話,就要給用戶說明爲何須要申請這個權限
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
                != PackageManager.PERMISSION_GRANTED) {
            // 權限未被授予
            requestCameraPermission();
        } else {
            Log.i(TAG, "相機權限已經被受理,開始預覽相機!");
            showCameraPreview();
        }
    }

    /**
     * 申請相機權限
     */
    private void requestCameraPermission() {
        Log.i(TAG, "相機權限未被授予,須要申請!");
        // 相機權限未被授予,須要申請!
        if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                Manifest.permission.CAMERA)) {
            // 若是訪問了,可是沒有被授予權限,則須要告訴用戶,使用此權限的好處
            Log.i(TAG, "申請權限說明!");
            Snackbar.make(mLayout, R.string.permission_camera_rationale,
                    Snackbar.LENGTH_INDEFINITE)
                    .setAction(R.string.ok, new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            // 這裏從新申請權限
                            ActivityCompat.requestPermissions(MainActivity.this,
                                    new String[]{Manifest.permission.CAMERA},
                                    REQUEST_CAMERA);
                        }
                    })
                    .show();
        } else {
            // 第一次申請,就直接申請
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA},
                    REQUEST_CAMERA);
        }
    }

    public void showContacts(View v) {
        // 判斷權限是否擁有
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS)
                != PackageManager.PERMISSION_GRANTED
                || ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_CONTACTS)
                != PackageManager.PERMISSION_GRANTED) {
            Log.i(TAG, "讀寫聯繫人權限未被授予,須要申請!");
            // 讀寫聯繫人權限未被授予,須要申請!
            requestContactsPermissions();
        } else {
            // 權限已經被授予,顯示細節頁面!
            Log.i(TAG, "權限已經被授予,顯示細節頁面!");
            showContactDetails();
        }
    }

    /**
     * 申請聯繫人讀取權限
     */
    private void requestContactsPermissions() {
        if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                Manifest.permission.READ_CONTACTS)
                || ActivityCompat.shouldShowRequestPermissionRationale(this,
                Manifest.permission.WRITE_CONTACTS)) {
            // 若是是第二次申請,須要向用戶說明爲什麼使用此權限,會帶出一個再也不詢問的複選框!
            Log.i(TAG, "若是是第二次申請,須要向用戶說明爲什麼使用此權限,會帶出一個再也不詢問的複選框!");

            Snackbar.make(mLayout, R.string.permission_contacts_rationale,
                    Snackbar.LENGTH_INDEFINITE)
                    .setAction(R.string.ok, new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            ActivityCompat
                                    .requestPermissions(MainActivity.this, PERMISSIONS_CONTACT,
                                            REQUEST_CONTACTS);
                        }
                    })
                    .show();
        } else {
            // 第一次申請此權限,直接申請
            ActivityCompat.requestPermissions(this, PERMISSIONS_CONTACT, REQUEST_CONTACTS);
        }
    }

    /**
     * 顯示相機預覽界面
     */
    private void showCameraPreview() {
        getSupportFragmentManager().beginTransaction()
                .replace(R.id.sample_content_fragment, CameraPreviewFragment.newInstance())
                .addToBackStack("contacts")
                .commit();
    }

    /**
     * 顯示聯繫人頁面
     */
    private void showContactDetails() {
        getSupportFragmentManager().beginTransaction()
                .replace(R.id.sample_content_fragment, ContactsFragment.newInstance())
                .addToBackStack("contacts")
                .commit();
    }


    /**
     * 申請權限的回調,
     *
     * @param requestCode  requestCode
     * @param permissions  permissions
     * @param grantResults grantResults 多個權限一塊兒返回
     */
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
                                           @NonNull int[] grantResults) {
        if (requestCode == REQUEST_CAMERA) {
            if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                Snackbar.make(mLayout, R.string.permision_available_camera,
                        Snackbar.LENGTH_SHORT).show();
            } else {
                Snackbar.make(mLayout, R.string.permissions_not_granted,
                        Snackbar.LENGTH_SHORT).show();
            }
        } else if (requestCode == REQUEST_CONTACTS) {
            // 這裏有個多權限的檢查,須要檢查每個權限是否都被受權了
            if (PermissionUtil.verifyPermissions(grantResults)) {
                // true,全部權限已經被授予
                Snackbar.make(mLayout, R.string.permision_available_contacts,
                        Snackbar.LENGTH_SHORT)
                        .show();
            } else {
                // false,並非全部權限都被授予
                Snackbar.make(mLayout, R.string.permissions_not_granted, Snackbar.LENGTH_SHORT).show();
            }
        } else {
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        MenuItem logToggle = menu.findItem(R.id.menu_toggle_log);
        logToggle.setVisible(findViewById(R.id.sample_output) instanceof ViewAnimator);
        logToggle.setTitle(mLogShown ? R.string.sample_hide_log : R.string.sample_show_log);
        return super.onPrepareOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.menu_toggle_log:
                mLogShown = !mLogShown;
                ViewAnimator output = (ViewAnimator) findViewById(R.id.sample_output);
                if (mLogShown) {
                    output.setDisplayedChild(1);
                } else {
                    output.setDisplayedChild(0);
                }
                supportInvalidateOptionsMenu();
                return true;
        }
        return super.onOptionsItemSelected(item);
    }

    /**
     * 初始化log日誌
     */
    @Override
    public void initializeLogging() {
        LogWrapper logWrapper = new LogWrapper();
        Log.setLogNode(logWrapper);

        MessageOnlyLogFilter msgFilter = new MessageOnlyLogFilter();
        logWrapper.setNext(msgFilter);

        LogFragment logFragment = (LogFragment) getSupportFragmentManager()
                .findFragmentById(R.id.log_fragment);
        msgFilter.setNext(logFragment.getLogView());
    }

    public void onBackClick(View view) {
        // 由於咱們對fragment入棧處理,按返回鍵的時候,出棧處理
        getSupportFragmentManager().popBackStack();
    }

}

第一,咱們申請權限的方法:

ActivityCompat.requestPermissions(final @NonNull Activity activity,
            final @NonNull String[] permissions, final @IntRange(from = 0) int requestCode){}

第二,是申請的結果回調方法:

public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
                                           @NonNull int[] grantResults){}


以上就是主要的兩個方法了。

固然,還要注意一下,是不是第一次申請權限?需不須要想用戶說明我這個權限是用來幹嗎的?若是用戶不受權,個人APP該如何來操做防止崩潰?用戶隨時能夠取消對你APP的受權,那時咱們又該如何來作?

問題好多好多,咱們要走的路還很長。可是我這裏有幾個方法,適合你們去咀嚼咀嚼。

第一個:

ActivityCompat.shouldShowRequestPermissionRationale(this,

                Manifest.permission.READ_CONTACTS)

這個方法呢,說的是,當你第一次去請求權限的時候,若是用戶拒絕了,而後第二次再去申請此權限,那麼這個方法會返回一個true的結果,告訴你,上一次用戶不一樣意給你這個權限,而後此次你就須要向用戶說明爲何你須要這個權限。


咱們看到的效果圖,是有相機預覽和查看聯繫人的頁面的,這裏我就不一一把代碼貼出來,我會在最後面把工程代碼放到GitHub上面,給你們下載。裏面有更加詳細的說明。

代碼下載:點擊打開連接

若有任何問題,請及時與我聯繫,謝謝!

相關文章
相關標籤/搜索