Android7.0新特性,及Android N適配


新特性部分

Android 7.0 Nougat 提供新功能以提升性能、生產效率和安全性,主要新增了下面的新特性和優化:

一、新的Notification

Android N 添加了很多新的notifications API,進行了又一次的設計,引入了新的風格。

  • 模板更新: 開發人員將能夠充分利用新模板,僅僅需進行少量的代碼調整。
  • 消息樣式自己定義: 新增自己定義樣式、消息回復、消息分組等更加靈活。

  • 捆綁通知: 系統能夠將消息組合在一起(比如,按消息主題)並顯示組。用戶能夠適當地進行 Dismiss 或 Archive 等操作。
  • 直接回復: 對於實時通信應用。Android 系統支持內聯回復,以便用戶能夠直接在通知界面中高速回復短信。
  • 自己定義視圖: 兩個新的 API ,在通知中使用自己定義視圖時能夠充分利用系統裝飾元素,如通知標題和操作。

這里寫圖片描寫敘述


二、多窗體支持(分屏模式)

  • 手機和平板: 用戶能夠並排運行兩個應用,或者處於分屏模式時一個應用位於還有一個應用之上。用戶能夠通過拖動兩個應用之間的分隔線來調整應用。

  • Android TV: 應用能夠將自身置於畫中畫模式。從而讓它們能夠在用戶瀏覽或與其它應用交互時繼續顯示內容。

這里寫圖片描寫敘述


三、Quick Settings Tile API

高速設置”通經常使用於直接從通知欄顯示關鍵設置和操作。非常easy。在 Android N中。已擴展“高速設置”的范圍,使其更加實用更方便。為額外的“高速設置”圖塊加入了很多其它空間,用戶能夠通過向左或向右滑動跨分頁的顯示區域訪問它們。

還讓用戶能夠控制顯示哪些“高速設置”圖塊以及顯示的位置 — 用戶能夠通過拖放圖塊來加入或移動圖塊。

對於開發人員,Android N 還加入了一個新的 API。從而能夠定義自己的“高速設置”圖塊,使用戶能夠輕松訪問應用中的關鍵控件和操作。

這里寫圖片描寫敘述


四、高速的應用安裝路徑

Android 運行組件的 JIT 編譯器最實際的優點之中的一個是應用安裝和系統更新的速度。

即使在Android 6.0 中須要幾分鍾進行優化和安裝的大型應用,如今僅僅需幾秒鍾就能夠完畢安裝。系統更新也變得更快,由於省去了優化步驟。


五、隨時隨地低電耗模式

在 Android N 中。低電耗模式又前進了一步,隨時隨地能夠省電。

僅僅要屏幕關閉了一段時間。且設備未插入電源,低電耗模式就會相應用使用熟悉的 CPU 和網絡限制。這意味着用戶即使將設備放入口袋里也能夠省電。


六、Project Svelte:后台優化

Project Svelte在持續改善,以最大程度降低生態系統中一系列 Android 設備中系統和應用使用的 RAM。在 Android N 中,Project Svelte 注重優化在后台中運行應用的方式。

后台處理是大多數應用的一個重要部分。

處理得當,可實現非常棒的用戶體驗—即時、高速和情境感知。假設處理不得當,后台處理會毫無必要地消耗 RAM和電池,同一時候影響其它應用的系統性能。

Android N 刪除了三項隱式廣播(CONNECTIVITY_ACTION、ACTION_NEW_PICTURE 和ACTION_NEW_VIDEO)
。以幫助優化內存使用和電量消耗。

此項變更非常有必要,由於隱式廣播會在后台頻繁啟動已注冊偵聽這些廣播的應用,刪除這些廣播能夠顯著提升設備性能和用戶體驗。

移動設備會經歷頻繁的連接變更,比如在 Wi-Fi 和移動數據之間切換時。眼下,能夠通過在應用清單文件里注冊一個接收器來偵聽隱式 CONNECTIVITY_ACTION廣播,讓應用能夠監控這些變更。由於非常多應用會注冊接收此廣播,因此單次網絡切換即會導致全部應用被喚醒並同一時候處理此廣播。同理,應用能夠注冊接收來自其它應用(比如相機)的隱式ACTION_NEW_PICTURE 和ACTION_NEW_VIDEO 廣播。當用戶使用相機應用拍攝照片時。這些應用即會被喚醒處理廣播。

為減緩這些問題。Android N應用了下面優化措施:

1、面向 Android N 開發的應用不會收到 CONNECTIVITY_ACTION 廣播,即使它們已有清單條目來請求接受這些事件的通知。在前台運行的應用假設使用BroadcastReceiver請求接收通知,則仍能夠在主線程中偵聽CONNECTIVITY_CHANGE。

2、 應用無法發送或接收 ACTION_NEW_PICTURE 和ACTION_NEW_VIDEO廣播。此項優化會影響全部應用,而不僅僅是面向 Android N 的應用。

未來的 Android 版本號還可能會棄用其它隱式廣播以及未綁定的后台服務。有鑒於此。應避免依賴在清單文件里聲明的接收器來偵聽隱式廣播或刪除此依賴關系,以及避免或刪除對后台服務的依賴關系。

Android 框架提供多種解決方式來降低這些隱式廣播或后台服務的必要性。比如,JobScheduler API 提供了一個穩健可靠的機制來安排滿足指定條件(比如連入不按流量計費的網絡)時所運行的網絡操作。甚至能夠使用JobScheduler來響應內容提供程序所發生的變更。


七、Data Saver

在移動設備的整個生命周期。蜂窩數據計划的成本一般會超出設備本身的成本。對於很多用戶而言。蜂窩數據是他們想要節省的昂貴資源。

Android N推出了Data Saver模式,這是一項新的系統服務,有助於降低應用使用的蜂窩數據,不管是在漫游,賬單周期即將結束。還是使用少量的預付費數據包。

Data Saver讓用戶能夠控制應用使用蜂窩數據的方式。同一時候讓開發人員打開Data Saver時能夠提供很多其它有效的服務。

這里寫圖片描寫敘述


八、Data Saver

Android N 將一項新的 3D 渲染 API Vulkan™ 集成到平台中。就像 OpenGL™ ES 一樣,Vulkan是 3D 圖形和渲染的一項開放標准。由Khronos Group 維護。

Vulkan是全然從零開始設計,以最小化驅動器中的 CPU 開銷,並能讓應用更直接地控制 GPU 操作。Vulkan還同意多個線程同一時候運行工作。如命令緩沖區構建。以獲得更好的並行化。

Vulkan開發工具和庫都已卷入Android NDK。

它們包含:

● 頭
● 驗證層(調試庫)
● SPIR-V 着色程序編譯器
● SPIR-V 運行時着色器編譯庫
● Vulkan僅適用於已啟用Vulkan硬件的設備上的應用。如 Nexus 5X、Nexus 6P 和Nexus Player。


九、號碼屏蔽

Android N 如今支持在平台中進行號碼屏蔽。提供框架 API,讓服務提供商能夠維護屏蔽的號碼列表。

默認短信應用、默認手機應用和提供商應用能夠對屏蔽的號碼列表進行讀取和寫入操作。其它應用則無法訪問此列表。


十、來電過濾

Android N 同意默認的手機應用過濾來電。手機應用運行此操作的方式是實現新的CallScreeningService。該方法同意手機應用基於來電的Call.Details運行大量操作,比如:

● 拒絕來電
● 不同意來電到達通話記錄
● 不向用戶顯示來電通知


十一、多區域設置支持、多語言

Android N 如今同意用戶在設置中選擇多個區域設置,以更好地支持雙語用例。

應用能夠使用新的 API 獲取用戶選擇的區域設置,然后為多區域設置用戶提供更成熟的用戶體驗,如以多個語言顯示搜索結果,而且不會以用戶了解的語言翻譯網頁。

除多區域設置支持外,Android N 還擴展了用戶可用的語言范圍。它針對經常使用語言提供超過 25種的變體,如英語、西班牙語、法語和阿拉伯語。它還針對 100 多種新語言加入了部分支持。

應用能夠通過調用 LocaleList.GetDefault() 獲取用戶設置的區域設置列表。

為支持擴展的區域設置數量。Android N 正在改變其解析資源的方式。


十二、新增的表情符號

Android N引入很多其它表情符號和表情符號相關功能,包含膚色表情符號和支持變量選擇符。假設應用支持表情符號,請遵循下面准則,以便能充分利用這些表情符號相關功能優勢。

  • 在插入之前,檢查設備是否包含表情符號。 若要檢查系統字體中有哪些表情符號。使用hasGlyph(String) 方法。
  • 檢查表情符號是否支持變量選擇符。 變量選擇符能夠呈現一些彩色或黑白的表情符號。在移動設備上。應用應呈現彩色的表情符號,而不是黑白的。

    可是,假設應用顯示嵌入在文本中的表情符號。那應使用黑白變量。若要確定表情符號是否有變量,使用變量選擇符。如需有關支持變量的字符的完整清單,請參閱變量的 Unicode 文檔中的表情符號變量序列部分。

  • * 檢查表情符號是否支持膚色。* Android N同意用戶依照他們的喜好改動表情符號呈現的膚色。鍵盤應用應為有多個膚色的表情符號提供可視化的指示。並應同意用戶選擇他們喜歡的膚色。

    若要確定哪些系統表情符號有膚色改動器,使用hasGlyph(String) 方法。能夠通過讀取Unicode 文檔來確定哪些表情符號使用膚色。


十三、Android 中的 ICU4J API

ICU4J 是一個廣泛使用的開源 Java 庫集合,為軟件應用提供 Unicode 和全球化支持。Android N 在android.icu軟件包下顯示 Android 框架中的 ICU4J API 子集,供應用開發人員使用。

遷移非常easy,主要是須要從com.java.icu命名空間更改為android.icu。假設已在應用中使用 ICU4J 捆綁包,切換到 Android 框架中提供的android.icu API 能夠大量節省 APK 大小。


十四、OpenGL™ ES 3.2 API

Android N 加入了框架接口和對 OpenGL ES 3.2 的平台支持。包含:
● 來自 Android 擴展包 (AEP) 的全部擴展(EXT_texture_sRGB_decode除外)。
● 針對 HDR 的浮點幀緩沖和延遲着色。
● Android N同意用戶依照他們的喜好改動表情符號呈現的膚色。鍵盤應用應為有多個膚色的表情符號提供可視化的指示,並應同意用戶選擇他們喜歡的膚色。若要確定哪些系統表情符號有膚色改動器。使用hasGlyph(String) 方法。

能夠通過讀取Unicode 文檔來確定哪些表情符號使用膚色。
● BaseVertex畫圖調用可實現更好的批處理和流媒體服務。
● 強大的緩沖區訪問控制可降低WebGL開銷。


十五、VR 支持

(面向Android的 Google VR SDK)

Android N 加入了新的VR 模式的平台支持和優化,以使開發人員能為用戶打造高質量移動 VR體驗。新版針對開發人員提供了大量性能增強特性。包含單一緩沖區渲染以及同意 VR 應用訪問某個專屬的CPU 核心。在應用中,能夠享受到專為 VR 設計的平滑頭部跟蹤和立體聲通知功能。

這里寫圖片描寫敘述


十六、無障礙增強功能

(API參考 android.accessibilityservice.GestureDescription)

Android N 如今針對新的設備設置直接在歡迎屏幕上提供“Vision Settings”。這使用戶能夠更easy發現和配置他們設備上的無障礙功能,包含放大手勢、字體大小、顯示屏尺寸和TalkBack。


十七、密鑰認證

使用硬件支持的密鑰庫。可更安全地在 Android 設備上創建、存儲和使用加密密鑰。

它們可保護密鑰免受 Linux 內核、潛在的 Android 漏洞的攻擊。也可防止從已取得根權限的設備提取密鑰。

為了讓硬件支持的密鑰庫使用起來更簡單和更安全。Android N 引入了密鑰認證。應用和關閉的設備可使用密鑰認證以堅決地確定 RSA 或 EC 密鑰對是否受硬件支持、密鑰對的屬性怎樣,以及其使用和有效性有何限制。

應用和關閉的設備服務能夠通過 X.509 認證證書(必須由有效的認證密鑰簽署)請求有關密鑰對的信息。

認證密鑰是一個 ECDSA 簽署密鑰,其在出廠時被注入設備的硬件支持的密鑰庫。

因此。有效的認證密鑰簽署的認證證書可確認硬件支持的密鑰庫是否存在。以及該密鑰庫中密鑰對的具體信息。

為確保設備使用安全的官方 Android 出廠映像,密鑰認證要求設備 bootloader向可信運行環境(TEE)提供下面信息:

設備上安裝的操作系統版本號和補丁級別
● 驗證的啟動公鑰和鎖定狀態。
● 除密鑰認證外,Android N 還推出了指紋綁定密鑰,在指紋注冊時不會撤銷。


適配部分

在Android 7.0 的適配中,遇到了些問題,主要是新特性上的一些變化,須要針對性的做適配。

一、權限更改

隨着Android版本號越來越高,Android對隱私的保護力度也越來越大。

從Android6.0引入的動態權限控制(Runtime Permissions)到Android7.0的“私有文件夾被限制訪問”,“StrictMode API 政策”。這些更改在為用戶帶來更加安全的操作系統的同一時候也為開發人員帶來了一些新的任務。怎樣讓你的APP能夠適應這些改變而不是cash,是擺在每一位Android開發人員身上的責任。

二、文件夾被限制訪問

隨着Android版本號越來越高,Android對隱私的保護力度也越來越大。

從Android6.0引入的動態權限控制(Runtime Permissions)到Android7.0的“私有文件夾被限制訪問”,“StrictMode API 政策”。這些更改在為用戶帶來更加安全的操作系統的同一時候也為開發人員帶來了一些新的任務。怎樣讓你的APP能夠適應這些改變而不是cash,是擺在每一位Android開發人員身上的責任。

● 私有文件的文件權限不在放權給全部的應用,使用 MODE_WORLD_READABLE 或 MODE_WORLD_WRITEABLE 進行的操作將觸發 SecurityException。

應對策略:這項權限的變更將意味着你無法通過File API訪問手機存儲上的數據了。基於File API的一些文件瀏覽器等也將受到非常大的影響,看到這大家是不是驚呆了呢,只是迄今為止,這樣的限制尚不能全然運行。

應用仍可能使用原生 API 或 File API 來改動它們的私有文件夾權限。 可是,Android官方強烈反對放寬私有文件夾的權限。

能夠看出收起對私有文件的訪問權限是Android將來發展的趨勢。

● 給其它應用傳遞 file:// URI 類型的Uri,可能會導致接受者無法訪問該路徑。 因此,在Android7.0中嘗試傳遞 file:// URI 會觸發 FileUriExposedException。

應對策略:大家能夠通過使用FileProvider來解決這一問題。

● DownloadManager 不再按文件名稱分享私人存儲的文件。

COLUMN_LOCAL_FILENAME在Android7.0中被標記為deprecated, 舊版應用在訪問 COLUMN_LOCAL_FILENAME時可能出現無法訪問的路徑。

面向 Android N 或更高版本號的應用在嘗試訪問 COLUMN_LOCAL_FILENAME 時會觸發 SecurityException。

應對策略:大家能夠通過ContentResolver.openFileDescriptor()來訪問由 DownloadManager 公開的文件。

三、應用間共享文件

在Android7.0系統上。Android 框架強制運行了 StrictMode API 政策禁止向你的應用外公開 file:// URI。

假設一項包含文件 file:// URI類型 的 Intent 離開你的應用,應用失敗,並出現 FileUriExposedException 異常,如調用系統相機拍照,或裁切照片。

應對策略:若要在應用間共享文件。能夠發送 content:// URI類型的Uri,並授予 URI 暫時訪問權限。 進行此授權的最簡單方式是使用 FileProvider類。 如需有關權限和共享文件的很多其它信息,請參閱共享文件。


● 給其它應用傳遞 file:// URI 類型的Uri。可能會導致接受者無法訪問該路徑。

因此。在Android7.0中嘗試傳遞 file:// URI 會觸發 FileUriExposedException。


實例問題

調用系統相機拍照,裁切照片。
在Android7.0之前,假設你想調用系統相機拍照能夠通過下面代碼來進行:

File file=new File(Environment.getExternalStorageDirectory(), "/temp/"+System.currentTimeMillis() + ".jpg");
if (!file.getParentFile().exists())file.getParentFile().mkdirs();
Uri imageUri = Uri.fromFile(file);
Intent intent = new Intent();
intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);//設置Action為拍照
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);//將拍取的照片保存到指定URI
startActivityForResult(intent,1006);

在Android7.0上使用上述方式調用系統相拍照會拋出例如以下異常:

android.os.FileUriExposedException: file:////storage/emulated/0/temp/1474956193735.jpg exposed beyond app through Intent.getData()
at android.os.StrictMode.onFileUriExposed(StrictMode.java:1799)
at android.net.Uri.checkFileUriExposed(Uri.java:2346)
at android.content.Intent.prepareToLeaveProcess(Intent.java:8933)
at android.content.Intent.prepareToLeaveProcess(Intent.java:8894)
at android.app.Instrumentation.execStartActivity(Instrumentation.java:1517)
at android.app.Activity.startActivityForResult(Activity.java:4223)
...
at android.app.Activity.startActivityForResult(Activity.java:4182)

閃退截圖例如以下:

這里寫圖片描寫敘述

這是由於Android7.0運行了“StrictMode API 政策禁”的原因,只是小伙伴們不用操心,上文講到了能夠用FileProvider來解決這一問題,
如今我們就來一步一步的解決問題。

使用FileProvider
使用FileProvider的大致過程例如以下:

第一步:在manifest清單文件里注冊provider

<provider  android:name="android.support.v4.content.FileProvider" android:authorities="com.jph.takephoto.fileprovider" android:grantUriPermissions="true" android:exported="false">
    <meta-data  android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" />
</provider>

心得:exported:要求必須為false,為true則會報安全異常。grantUriPermissions:true,表示授予 URI 暫時訪問權限。

第二步:指定共享的文件夾

為了指定共享的文件夾我們須要在資源(res)文件夾下創建一個xml文件夾,然后創建一個名為“file_paths”(名字能夠隨便起,僅僅要和在manifest注冊的provider所引用的resource保持一致就可以)的資源文件。內容例如以下:

<?

xml version="1.0" encoding="utf-8"?> <resources> <paths> <external-path path="" name="camera_photos" /> </paths> </resources>

代表的根文件夾: Context.getFilesDir()
代表的根文件夾: Environment.getExternalStorageDirectory()
代表的根文件夾: getCacheDir()

心得:上述代碼中path=”“,是有特殊意義的,它代碼根文件夾。也就是說你能夠向其它的應用共享根文件夾及其子文件夾下不論什么一個文件了,假設你將path設為path=”pictures”,
那么它代表着根文件夾下的pictures文件夾(eg:/storage/emulated/0/pictures),假設你向其它應用分享pictures文件夾范圍之外的文件是不行的。

第三步:使用FileProvider
上述准備工作做完之后,如今我們就能夠使用FileProvider了。


還是以調用系統相機拍照為例,我們須要將上述拍照代碼改動為例如以下:

File file=new File(Environment.getExternalStorageDirectory(), "/temp/"+System.currentTimeMillis() + ".jpg");
if (!file.getParentFile().exists())file.getParentFile().mkdirs();
Uri imageUri = FileProvider.getUriForFile(context, "com.jph.takephoto.fileprovider", file);//通過FileProvider創建一個content類型的Uri
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); //加入這一句表示對目標應用暫時授權該Uri所代表的文件
intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);//設置Action為拍照
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);//將拍取的照片保存到指定URI
startActivityForResult(intent,1006);

上述代碼中主要有兩處改變:

1、將之前Uri的scheme類型為file的Uri改成了有FileProvider創建一個content類型的Uri。
2、加入了intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);來對目標應用暫時授權該Uri所代表的文件。

心得:上述代碼通過FileProvider的Uri getUriForFile (Context context, String authority, File file)
靜態方法來獲取Uri,該方法中authority參數就是清單文件里注冊provider的android:authorities=”com.jph.takephoto.fileprovider”。


對Webserver如tomcat。IIS比較熟悉的小伙伴,都僅僅知道為了站點內容的安全和高效,Webserver都支持為站點內容設置一個虛擬文件夾,事實上FileProvider也有異曲同工之處。

將getUriForFile方法獲取的Uri打印出來例如以下:

content://com.jph.takephoto.fileprovider/camera_photos/temp/1474960080319.jpg。

當中camera_photos就是file_paths.xml中paths的name。

由於上述指定的path為path=”“,所以content://com.jph.takephoto.fileprovider/camera_photos/代表的真實路徑就是根文件夾,即:/storage/emulated/0/。
content://com.jph.takephoto.fileprovider/camera_photos/temp/1474960080319.jpg代表的真實路徑是:/storage/emulated/0/temp/1474960080319.jpg。

裁切照片代碼:

File file=new File(Environment.getExternalStorageDirectory(), "/temp/"+System.currentTimeMillis() + ".jpg");
if (!file.getParentFile().exists())file.getParentFile().mkdirs();
Uri outputUri = Uri.fromFile(file);
Uri imageUri=Uri.fromFile(new File("/storage/emulated/0/temp/1474960080319.jpg"));
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(imageUri, "image/*");
intent.putExtra("crop", "true");
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
intent.putExtra("scale", true);
intent.putExtra(MediaStore.EXTRA_OUTPUT, outputUri);
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
intent.putExtra("noFaceDetection", true); // no face detection
startActivityForResult(intent,1008);

和拍照一樣。上述代碼在Android7.0上相同會引起android.os.FileUriExposedException異常,解決的方法就是上文說說的使用FileProvider。

然后。將上述代碼改為例如以下就可以:

File file=new File(Environment.getExternalStorageDirectory(), "/temp/"+System.currentTimeMillis() + ".jpg");
if (!file.getParentFile().exists())file.getParentFile().mkdirs();
Uri outputUri = FileProvider.getUriForFile(context, "com.jph.takephoto.fileprovider",file);
Uri imageUri=FileProvider.getUriForFile(context, "com.jph.takephoto.fileprovider", new File("/storage/emulated/0/temp/1474960080319.jpg");//通過FileProvider創建一個content類型的Uri
Intent intent = new Intent("com.android.camera.action.CROP");
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setDataAndType(imageUri, "image/*");
intent.putExtra("crop", "true");
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
intent.putExtra("scale", true);
intent.putExtra(MediaStore.EXTRA_OUTPUT, outputUri);
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
intent.putExtra("noFaceDetection", true); // no face detection
startActivityForResult(intent,1008);

另外,裁切照片推薦大家使用開源工具庫TakePhoto,
TakePhoto是一款在Android設備上獲取照片(拍照或從相冊、文件里選擇)、裁剪圖片、壓縮圖片的開源工具庫。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM