AndroidStudyDemo之Android6.x新API介紹(一)

Android6.x新API介紹(一).png

作者:李旺成

時(shí)間:2016年4月19日


接上篇:AndroidStudyDemo之Android5.x新控件介紹(三)

新特性簡介

Android M

關(guān)于 Android 6 的新特性的文章非常多,這里我不打算做過多的介紹。在搜索了幾篇文章后,我對 Android 6 的新特性做了個(gè)簡單的分類(粗糙的分了下,別介),有興趣的可以稍微瞄一眼。

這里只是對 Android 6 的新特性做個(gè)簡單的總結(jié)歸納,為了縮短篇幅,就不貼圖了。想了解更多,可以下載文末的思維導(dǎo)圖,里面有備注。

硬件相關(guān)

  • 指紋識別
  • Doze 電量管理
  • 相機(jī)新增專業(yè)模式
  • 支持 RAW 格式照片
  • Chrome Custom Tabs
  • 外置存儲融入系統(tǒng)存儲中
  • 藍(lán)牙 SAP
  • 支持 MIDI
  • 支持 WIFI 熱點(diǎn)2.0
  • USB Type-C 端口支持

安全相關(guān)

  • 更完整的應(yīng)用權(quán)限管理
  • 啟動驗(yàn)證

體驗(yàn)優(yōu)化

  • 鎖屏下語音搜索
  • 支持 4K 顯示
  • 存儲管理
    支持文件夾拖拽應(yīng)用
  • Now on Tap功能
  • App Links
  • 改進(jìn)通知
  • Google Now Launcher
  • 文字選擇界面
  • 音量控制界面
  • 鎖屏界面
  • 直接分享
  • 全新的啟動動畫
  • 系統(tǒng)界面調(diào)諧器
    快速設(shè)置
    狀態(tài)欄
    顯示電池百分比
    演示模式

性能優(yōu)化

  • App Standby
  • 內(nèi)存管理

其他

  • Android Pay
  • 分屏顯示
  • USB 連接選項(xiàng)
  • 一些謎之特性
    消失的 Dark Theme
    改進(jìn)Android for Work
    整合Android Wear
    或許存在的一鍵關(guān)閉全部最近應(yīng)用
    增加信息中心
    更快的更新機(jī)制
    更開放應(yīng)用程序卸載選項(xiàng)

新 API 介紹#

一、動態(tài)權(quán)限申請

什么是動態(tài)權(quán)限申請

MIUI 權(quán)限申請頁面

動態(tài)權(quán)限申請也就是運(yùn)行時(shí)權(quán)限,是 Android 6.0 上帶來的權(quán)限管理新模式(就不說 iOS 上很早就有這個(gè)了,MIUI 上也很早就有了該特性...)。

在 6.0 以前,Android 對權(quán)限的處理是一刀切,就是安裝的時(shí)候給出一個(gè)權(quán)限列表提示,用戶同意了那就可以安裝(然后,就沒有然后了...)。而在 Android 6.0 以后,可以直接安裝,當(dāng) App 真正用到或者說申請某些權(quán)限時(shí),系統(tǒng)會給出讓用戶授權(quán)的提示,這時(shí)可以拒絕。當(dāng)然也提供了設(shè)置界面對每個(gè) App 的權(quán)限進(jìn)行管理。

Android 6.x 權(quán)限分類

在 Android 6.x 上對權(quán)限進(jìn)行了分類,包括正常權(quán)限和危險(xiǎn)權(quán)限。
正常權(quán)限:
定義:
訪問外部數(shù)據(jù)或操作的行為對用戶的隱私暴露風(fēng)險(xiǎn)很小的權(quán)限。
列舉:
ACCESS_LOCATION_EXTRA_COMMANDS
CHANGE_WIFI_STATE
FLASHLIGHT
SET_ALARM INSTALL_SHORTCUT
UNINSTALL_SHORTCUT

危險(xiǎn)權(quán)限:
定義:
需要訪問用戶的個(gè)人數(shù)據(jù),或是影響用戶已保存的數(shù)據(jù)時(shí)發(fā)生的權(quán)限。
列舉:
CALENDAE
READ_CALENDAR
WRITE_CALENDAR
CAMERA
CAMERA
CONTACTS
READ_CONTACTS
WRITE_CONTACTS
READ_PROFILE
WRITE_PROFILE
LOCATION
ACCESS_FINE_LOCATION
ACCESS_COARSE_LOCATION
MICROPHONE
RECORD_AUDIO
PHONE
READ_PHONE_STATE
CALL_PHONE
READ_CALL_LOG
WRITE_CALL_LOG
com.android.voicemail.permission.ADD_VOICEMAIL
USE_SIP
PROCESS_OUTGOING_CALLS
SENSORS
BODY_SENSORS
USE_FINGERPRINT
SMS
SEND_SMS
RECEIVE_SMS
READ_SMS
RECEIVE_WAP_PUSH
RECEIVE_MMS
READ_CELL_BROADCASTS
STORAGE
READ_EXTERNAL_STORAGE
WRITE_EXTERNAL_STORAGE

在 Android 6.x 上危險(xiǎn)權(quán)限進(jìn)行了分組處理,這有什么作用?

在 Android 6.x 上,授權(quán)機(jī)制是這樣的:如果 App 申請某個(gè)危險(xiǎn)的權(quán)限,假設(shè)該 App 已被授權(quán)過該組的某個(gè)權(quán)限,那么系統(tǒng)會立即授權(quán),而不需要用戶再點(diǎn)擊授權(quán)。

例如,如果你對某 App 授權(quán)過 SEND_SMS,那么當(dāng)該 App 申請 RECEIVE_SMS 等屬于 SMS Group 下的權(quán)限時(shí),系統(tǒng)會直接授權(quán)通過。

注意:上圖中的權(quán)限申請對話框上面的文本說明是對權(quán)限組的說明,而不是單個(gè)權(quán)限(PS:這個(gè)對話框是系統(tǒng)提供的)。

說明:在定義上述權(quán)限是,沒有給出前綴的,其前綴都是“ android.permission.”,這里為了清晰起見就沒有添加了。

Android 6.x 危險(xiǎn)權(quán)限處理

危險(xiǎn)權(quán)限處理流程

運(yùn)行時(shí)權(quán)限處理流程

通過上面的流程圖基本上可以了解 Andorid 6.x 對危險(xiǎn)權(quán)限的處理流程,這里就不再用文字描述。

權(quán)限處理相關(guān) API

先看看效果:

運(yùn)行時(shí)權(quán)限演示

1、檢查是否有權(quán)限

ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED

2、解釋權(quán)限申請?jiān)?,引?dǎo)用戶授權(quán)

if (!ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
    // 顯示對話框解釋為什么要申請權(quán)限
    showMessage("測試一下對SD卡進(jìn)行讀寫操作",
            new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog,
                                    int which) {
                    startAppSettings();
                }
            });
    return;
}

3、申請權(quán)限

ActivityCompat.requestPermissions(this,
        new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
        REQUEST_CODE_ASK_EXTERNAL_STORAGE_PERMISSON);

4、獲取用戶是否授權(quán)結(jié)果

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    switch (requestCode) {
        case REQUEST_CODE_ASK_EXTERNAL_STORAGE_PERMISSON:
            // Permission Granted
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                Toast.makeText(DynamicPermissionActivity.this, "用戶確認(rèn)授權(quán)操作SD卡權(quán)限", Toast.LENGTH_SHORT).show();
            } else { // Permission Denied
                Toast.makeText(DynamicPermissionActivity.this, "用戶拒絕授權(quán)操作SD卡權(quán)限", Toast.LENGTH_SHORT).show();
            }
            break;
        default:
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
            break;
    }
}

危險(xiǎn)權(quán)限測試

1、按組列出權(quán)限

$ adb shell pm list permissions -d -g
檢測權(quán)限的adb命令

2、開啟或者禁用某個(gè)權(quán)限

$ adb shell pm [grant|revoke] PACKAGE <permission-name>

示例:
$ adb shell pm grant com.diygreen.android6new android.permission.WRITE_EXTERNAL_STORAGE

自己去試試吧!這里就不貼圖了。

動態(tài)權(quán)限使用示例

1. 申請權(quán)限

<!--危險(xiǎn)權(quán)限-->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

2. 使用示例
示例代碼很簡單,直接看代碼:

private void testSDCardPermission() {
    if (mCheckSwitch.isChecked()) {
        // 1. 判斷是否有權(quán)限
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            // 在彈出權(quán)限選擇的對話框前給用戶show一個(gè)dialog,用于引導(dǎo)用戶進(jìn)行選擇
            if (!ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
                // 解釋為什么要申請權(quán)限
                showMessage("測試一下對SD卡進(jìn)行讀寫操作",
                        new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog,
                                                int which) {
                                startAppSettings();
                            }
                        });
                return;
            }
            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
                    REQUEST_CODE_ASK_EXTERNAL_STORAGE_PERMISSON);
        } else {
            Toast.makeText(DynamicPermissionActivity.this, "有權(quán)限了開始讀寫SD卡吧!", Toast.LENGTH_LONG).show();
        }
    } else {
        // 1. 判斷是否有權(quán)限
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED
                &&
                ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            // 2. 彈出對話框申請權(quán)限給用戶選擇
            // 第二個(gè)參數(shù)code與onRequestPermissionResult()方法中的code對應(yīng)
            ActivityCompat.requestPermissions(this, EXTERNAL_STORAGE_PERMISSIONS, REQUEST_CODE_ASK_EXTERNAL_STORAGE_PERMISSON);
        }  else {
            Toast.makeText(DynamicPermissionActivity.this, "有權(quán)限了開始讀寫SD卡吧!", Toast.LENGTH_LONG).show();
        }
    }
} 

private void showMessage(String message,
                             DialogInterface.OnClickListener okListener) {
    new AlertDialog.Builder(this)
            .setMessage(message)
            .setNegativeButton("取消", null)
            .setPositiveButton("設(shè)置", okListener).create().show();
}

// 啟動應(yīng)用的設(shè)置
private void startAppSettings() {
    Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
    intent.setData(Uri.parse(PACKAGE_URL_SCHEME + getPackageName()));
    startActivity(intent);
}

Fragment 中動態(tài)權(quán)限處理

在 Fragment 中動態(tài)權(quán)限的使用與 Activity 中稍有差別,有幾個(gè)需要注意的地方:

  1. 申請權(quán)限
    上面的示例程序中都是使用 ActivityCompat.requestPermissions() 靜態(tài)方法在 Activity 中申請權(quán)限的,可以看一下該方法的方法簽名:
public static void requestPermissions(final @NonNull Activity activity,
            final @NonNull String[] permissions, final int requestCode)

第一個(gè)參數(shù)是 Activity,當(dāng)然在 Fragment 中可以通過 getActivity() 方法獲取它所 attach 的 Activity,但這就導(dǎo)致了一個(gè)問題 —— requestPermissions() 方法是異步的,它的返回值會回調(diào)到第一個(gè)參數(shù)傳入的 Activity 中的 onRequestPermissionsResult() 方法上。

當(dāng)然,你可以將回調(diào)結(jié)果再傳給 Fragment,但是,這樣做不是平添了麻煩嘛。

這里可以直接使用 Fragment 中提供的 requestPermissions() 方法,這個(gè)是要注意的地方。

  1. Fragment 嵌套
    Fragment 嵌套往往有不少地方需要注意,在動態(tài)權(quán)限申請的時(shí)候也一樣。你會發(fā)現(xiàn)在嵌套的子 Fragment 中使用上述方法申請權(quán)限后,onRequestPermissionsResult() 回調(diào)方法并沒有執(zhí)行。其實(shí)解決的方法和剛才提過的思路是一樣的 —— 交給父 Fragment 去處理(上面的例子就是可以交給 Activity 去處理),然后再將回調(diào)結(jié)果傳給子 Fragment。

示例代碼:

// 在子 Fragment 中通過父 Fragment 申請權(quán)限
getParentFragment().requestPermissions(permissions, requestCode); 

// 在父 Fragment 中分發(fā)回調(diào)結(jié)果
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    List<Fragment> fragmentList = getChildFragmentManager().getFragments();
    if (fragmentList != null) {
        for (Fragment fragment : fragmentList) {
            if (fragment != null) {
                fragment.onRequestPermissionsResult(requestCode, permissions, grantResults);
            }
        }
    }
}

動態(tài)權(quán)限小結(jié)

  1. 動態(tài)權(quán)限相關(guān) API 建議使用靜態(tài)方法(兼容包中提高)
  2. 可嘗試使用第三方庫簡化代碼(這里不做介紹,有興趣自己去看看),例如:
    運(yùn)行時(shí)注解庫:PermissionGen
    編譯時(shí)注解庫:MPermissions
  3. 如果不使用第三方庫,建議使用工具類來管理危險(xiǎn)權(quán)限
  4. 在 Fragment 中處理動態(tài)權(quán)限的時(shí)候的一些注意事項(xiàng)
  5. 在 AndroidStudio 中會提醒檢測權(quán)限是否開啟,可以自動生成代碼
提醒檢測權(quán)限是否開啟

二、獲取硬件標(biāo)識符

簡介

在 Andorid 6.x 中,為了更好的保護(hù)用戶的數(shù)據(jù),移除了從代碼中通過 Wi-Fi 和藍(lán)牙的 API 訪問硬件標(biāo)識符。因此 WifiInfo.getMacAddress() 和BluetoothAdapter.getAddress() 將始終返回 02:00:00:00:00:00 而為了能夠通過Wi-Fi和藍(lán)牙掃描時(shí),獲取周邊設(shè)備的硬件標(biāo)識符,應(yīng)用必須具有ACCESS_FINE_LOCATION 和 ACCESS_COARSE_LOCATION權(quán)限:
WifiManager.getScanResults()
BluetoothDevice.ACTION_FOUND
BluetoothLeScanner.startScan()
(參考自:值得你關(guān)注的Android6.0上的重要變化(一)

注意:當(dāng)運(yùn)行 Android6.0(API level 23) 的設(shè)備啟動后臺 Wi-Fi 或藍(lán)牙掃描時(shí), 此操作對外部設(shè)備是可見的,且被顯示為一個(gè)隨機(jī)MAC的地址。

三、MIDI API

Android 6.x 提供了對 MIDI 的支持,這些 API 都在 android.media.midi 包下。MIDI API 可以用于從連接的 MIDI 輸入設(shè)備接收和播放 MIDI 信息。從 Google 的展示來看,幾乎任意可以輸出 MIDI 音符和 CC 數(shù)據(jù)的設(shè)備都可以。

MIDI 包

Google 提供了一個(gè)示例程序:Android MidiSynth。該示例程序演示了 MIDI API 的基本功能:

  • 枚舉當(dāng)前的可用設(shè)備(包括名稱、廠商、功能等)
  • 當(dāng) MIDI 設(shè)備插入或拔出時(shí)提示
  • 接收和處理 MIDI 信息
Android MidiSynth

這是官方提供的示例代碼運(yùn)行截圖,手邊沒有可以演示的設(shè)備,所以看不到什么數(shù)據(jù)。

本來打算分析一下該示例的源碼,本人實(shí)在是對這塊不了解,有興趣的童鞋自己下載代碼去看看吧。

Android MidiSynth 示例代碼
GitHub

四、直接分享

先看效果:

直接分享示例

上圖左側(cè)是直接分享本該有的效果,右側(cè)是在小米 Note(汗,目前只有這個(gè)手機(jī)可以測試)上的效果。有點(diǎn)坑,還以為是哪里寫錯(cuò)了,有原生系統(tǒng)的可以去試試。

簡介

Android 6 提供了直接分享的功能,允許用戶在一個(gè)應(yīng)用里面分享內(nèi)容到其他地方,比如聯(lián)系人。

核心思想是,用戶可以直接分享相關(guān)內(nèi)容而無需先打開一個(gè)的應(yīng)用程序再去分享,這樣直接分享允許用戶跳過通常的分享流程中的一個(gè)步驟。
(參考自:Implementing Android Marshmallow Direct Share

簡單使用

創(chuàng)建自定義 ChooserTargetService

ChooserTargetService 就是個(gè) Service,為直接分享提供 ChooserTarget 列表。
看下 ChooseTargetService 的繼承結(jié)構(gòu):

ChooseTargetService 類繼承結(jié)構(gòu).png

使用很簡單:

@TargetApi(Build.VERSION_CODES.M)
public class DirectShareService extends ChooserTargetService {

    @Override
    public List<ChooserTarget> onGetChooserTargets(ComponentName targetActivityName, IntentFilter matchedFilter) {
        ComponentName componentName = new ComponentName(getPackageName(),
                ShareActivity.class.getCanonicalName());
        ArrayList<ChooserTarget> targets = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            Bundle extras = new Bundle();
            extras.putInt("directsharekey", i);
            targets.add(new ChooserTarget(
                    "name_" + i,
                    Icon.createWithResource(this, R.mipmap.ic_logo),
                    0.5f,
                    componentName,
                    extras));
        }
        return targets;
    }
}

在清單文件中配置 ChooserTargetService

<service
    android:name=".newapi.DirectShareService"
    android:label="@string/app_name"
    android:permission="android.permission.BIND_CHOOSER_TARGET_SERVICE">
    <intent-filter>
        <action android:name="android.service.chooser.ChooserTargetService" />
    </intent-filter>
</service>

解釋一下上面的配置:

  1. 配置權(quán)限
    android:permission="android.permission.BIND_CHOOSER_TARGET_SERVICE"
  2. 配置 intent-filter
    <action android:name="android.service.chooser.ChooserTargetService" />

配置響應(yīng) ChooserTargetService 的 Activity

對于每一個(gè)你想要暴露給 ChooserTargetService 的 Activity,都需要加上 meta-data 。指定 name 是 android.service.chooser.chooser_target_service,在 Service 定義之前指明它的 value。當(dāng)一個(gè)隱式的 Intent 和其中一個(gè) Activity 匹配,這個(gè) intent 的選擇對話框?qū)@示包含這個(gè) Activity 的應(yīng)用的 ICON 同時(shí)還會顯示 ChooserTarget 列表的圖標(biāo)。選擇應(yīng)用的圖標(biāo)會像標(biāo)準(zhǔn)的分享 Intent 一樣,選擇 ChooserTarget icon 的時(shí)候會打開對應(yīng)的 Activity,根據(jù) Intent 傳遞過來的數(shù)據(jù)初始化數(shù)據(jù)(在 ChooserTargetService 中指定的)。
(參考自:實(shí)現(xiàn)安卓6.0的直接分享(Direct Share )功能

清單文件中配置:

<activity android:name=".newapi.ShareActivity">
    <intent-filter>
        <action android:name="android.intent.action.SEND" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="text/plain" />
    </intent-filter>
    <meta-data
        android:name="android.service.chooser.chooser_target_service"
        android:value=".newapi.DirectShareService" />
</activity>

發(fā)起直接分享 Intent

直接看代碼:

final Intent intent = new Intent(Intent.ACTION_SEND)
        .setType("text/plain")
        .putExtra(Intent.EXTRA_TITLE, "直接分享");
startActivity(Intent.createChooser(intent, "ChooserTargetService"));

示例 Demo

GitHub

未完待續(xù)...下一篇繼續(xù)介紹 Android 6.x 其余的新 API。

接下篇
AndroidStudyDemo之Android6.x新API介紹(二)

附件

Andoid6思維導(dǎo)圖

參考

Android 6.0有哪些新功能新特性 安卓6.0功能詳細(xì)介紹
Android 6.0 新功能和新特性
Android:Android 6.0新特性
Android 6.0新特性[zz]
作為 Android 史上最人性化的升級,Android M 的新功能全在這
Android M 部分API變動研究
6.0 版本的 Android M 加入了 MIDI API
Android 6.0 中的新技術(shù)總結(jié)
值得你關(guān)注的Android6.0上的重要變化(一)
值得你關(guān)注的Android6.0上的重要變化(二)
Everything every Android Developer must know about new Android’s Runtime Permission
Working with System Permissions
Permissions Best Practices
Android 6.0 運(yùn)行時(shí)權(quán)限處理完全解析
Android M 動態(tài)權(quán)限獲取
Android 6.0: 動態(tài)權(quán)限管理的解決方案
android 6.0權(quán)限全面詳細(xì)分析和解決方案
Android M 動態(tài)權(quán)限獲取
Android 6.0 運(yùn)行時(shí)權(quán)限處理
在Android 6.0 設(shè)備上動態(tài)獲取權(quán)限
Implementing Android Marshmallow Direct Share
安卓6.0新特性:直接分享功能

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,030評論 25 709
  • 片段二非暴力溝通 I書簽 大多數(shù)人忽視自己的感受,無法表達(dá)自己的感受,而是更加傾向于表達(dá)看法,一種自認(rèn)為正確的權(quán)威...
    miyou5x閱讀 533評論 0 0
  • 膠南鎮(zhèn)是有名的木匠之鄉(xiāng),出師的木匠個(gè)個(gè)都手藝塞魯班,每年從各地來慕名學(xué)手藝的人接踵而至,一波又一波青壯小伙...
    故人驚蟄東來閱讀 373評論 0 0
  • 當(dāng)我走到克萊爾身邊的時(shí)候,她此刻目不轉(zhuǎn)睛的盯著這幅畫。 我抬頭看看這幅畫,頓時(shí)被這幅畫強(qiáng)烈的神秘感吸引。 我頓時(shí)有...
    商業(yè)探長阿朝閱讀 409評論 0 0
  • 月近中秋風(fēng)漸涼,熒光投影上孤墻。 千載不變風(fēng)和月,情絲依舊難思量。
    落魄山知了猴閱讀 359評論 0 0

友情鏈接更多精彩內(nèi)容