歡迎光臨
每天分享高質量文章

Android 適配之版本適配

作者:南歌ccc
連結:https://www.jianshu.com/p/db0f8deecd8b

這篇文章用來記錄學習和開發時遇到的版本適配問題,持續更新

Android9.0即 API28-適配

  • 全面屏、劉海屏的適配:

Android 9 支援最新的全面屏,其中包含為攝像頭和揚聲器預留空間的螢幕缺口。
透過 DisplayCutout 類可確定非功能區域的位置和形狀,這些區域不應顯示內容。
要確定這些螢幕缺口區域是否存在及其位置,使用 getDisplayCutout()函式。

LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT:

只有當DisplayCutout完全包含在系統欄中時,才允許視窗擴充套件到 DisplayCutout區域。否則,視窗的佈局不會與顯示剪下區域重疊。

LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES:

螢幕短邊有cutout,會延伸過去;若cutout在長邊,一定不會延伸過去。

LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER:

視窗決不允許與顯示剪下區域重疊。

設定程式碼:

WindowManager.LayoutParams lp = getWindow().getAttributes();
lp.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
getWindow().setAttributes(lp);
  • 通知功能的變更

Android 8.0 引入了通知渠道,允許您為要顯示的每種通知型別建立可由使用者自定義的渠道。 Android 9 透過下列變更簡化通知渠道設定:

1.)遮蔽渠道組:現在,使用者可以針對某個應用在通知設定中遮蔽整個渠道組。 您可以使用 isBlocked() 函式確定何時遮蔽一個渠道組,從而不會向該組中的渠道傳送任何通知。
此外,您的應用可以使用全新的 getNotificationChannelGroup() 函式查詢當前渠道組設定。

2.)全新的廣播 Intent 型別:現在,當通知渠道和渠道組的遮蔽狀態發生變更時,Android 系統將傳送廣播 Intent。 擁有已遮蔽的渠道或渠道組的應用可以偵聽這些 Intent 並做出相應的回應。

有關這些 Intent 操作和 extra 的更多資訊,請參閱 NotificationManager 參考中更新的常量串列。 有關響應廣播 Intent 的資訊,請參閱廣播。

  • 許可權收緊

1.)為了增強使用者隱私,Android 9 引入了若干行為變更,如限制後臺應用訪問裝置感測器、限制透過 Wi-Fi 掃描檢索到的資訊,以及與通話、手機狀態和 Wi-Fi 掃描相關的新許可權規則和許可權組。

無論採用哪一種標的 SDK 版本,這些變更都會影響執行於 Android 9 上的所有應用。

2.)Android 9 限制後臺應用訪問使用者輸入和感測器資料的能力。

如果您的應用在執行 Android 9 裝置的後臺執行,系統將對您的應用採取以下限制:

您的應用不能訪問麥克風或攝像頭。
使用連續報告樣式的感測器(例如加速度計和陀螺儀)不會接收事件。
使用變化或一次性報告樣式的感測器不會接收事件。
如果您的應用需要在執行 Android 9 的裝置上檢測感測器事件,請使用前臺服務。

  • 對使用非 SDK 介面的限制

目前處理方式掃描程式碼,避免使用或者使用類似的替代方法,如果避免不了,最粗暴的是try-catch,正統做法是每處都做if-else的Android9適配,如果是第三方庫,可以遮蔽入口,或者反編譯sdk處理,
處理起來比較複雜,官方受限制名單也還沒完全確定,等待後續解決辦法吧。

Android8.0即 API26~27適配

  • 自定義icon-launcher圖示

  • 通知相關修改

1.)通知渠道組 NotificationChannel,渠道ID channelId的規則,大改很多,包括提供了應用桌面圖示有通知顯示小圓點,長按圖示還能進行訊息操作等
顯示小圓點:

channel.setShowBadge(true);

右上角還有一個數字角標:

Notification.Builder builder=new Notification.Builder(this, channelId);
builder.setNumber(10);

通知超時:

Notification.Builder builder=new Notification.Builder(this, channelId);
builder.setTimeoutAfter(timeout*1000)

背景顏色:這個屬性要生效,必須是持續任務,且是前臺服務

builder.setColorized(true);
builder.setColor(Color.BLACK);

通知清除回呼:

系統現在可區分通知是由使用者清除,還是由應用自己移除。要檢視清除通知的方式,應實現 NotificationListenerService 類的新 onNotificationRemoved() 方法
AndroidManifest 裡面不要忘記加配置,這麼做,我還是可以保證你沒有任何回呼會發生,因為這裡面有個別別竅,要手動開啟通知訪問許可權。來看模擬器上的操作流程,設定>應用和通知>高階>特殊應用許可權->通知使用權
透過判斷第三個引數reason是REASON_CANCEL還是REASON_LISTENER_CANCEL就可以知道是使用者刪除還是系統刪除了

  • 後臺服務限制

在後臺中執行的服務會消耗系統資源,這可能降低使用者體驗。 為了緩解這一問題,系統對這些服務施加了一些限制。那麼什麼情況下應用被視為處於前臺?

1.)具有可見Activity(不管該Activity已啟動還是已暫停)
2.)具有前臺服務
3.)另一個前臺應用已關聯到該應用(不管是透過系結到其中一個服務,還是透過使用其中一個內容提供程式)。

例如,如果另一個應用系結到該應用的服務,那麼該應用處於前臺:輸入法、桌布服務、語音等

如果以上條件均不滿足,應用將被視為處於後臺。

startForegroundService方法呼叫後,記得5秒鐘內呼叫startForeground方法,否則系統將停止服務並宣告此應用為ANR。具體使用看官方檔案即可,不做贅述。

4.)後臺位置限制:

之前說的後臺服務限制目前只針對標的SDK版本為8.0的app,但是涉及到後臺位置限制就是所有版本SDK都要調整的了,它限制後臺應用每小時只接收幾次位置更新。
當然,解決的辦法是一樣的,依然是建立前臺服務

  • Android 8.0去除“允許未知來源”選項,需手動確認。

如果我們的App具備安裝App的功能,那麼AndroidManifest檔案需要包含REQUEST_INSTALL_PACKAGES許可權,未宣告此許可權的應用將無法安裝其他應用。

我們可以選擇使用 Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES這個action將使用者引導至安裝未知應用許可權介面。

同時也可以使用 packageManager.canRequestPackageInstalls()查詢此許可權的狀態
不過最簡單的辦法就是直接在AndroidManifest中配置一下就行了,這樣會在App呼叫安裝介面的同時,系統會自動詢問使用者完成授權,體驗尚可。

  • 懸浮窗相關

這個東西篇幅較長,使用頻率不高,後面可能會單獨一篇文章說這個,在此便不做贅述,有興趣的可自行瞭解。

Android7.0即API24~25適配

  • FileProvider

對於app標的版本大於等於24的應用,禁止在應用外部公開 file:// URI , 如果一項包含檔案 URI 的 intent 離開應用,則應用出現 FileUriExposedException 異常。

要應用間共享檔案,您應傳送一項 content:// URI,並授予 URI 臨時訪問許可權。進行此授權的最簡單方式是使用 FileProvider類。如需瞭解有關許可權和共享檔案的詳細資訊,請參閱官方檔案。

FileProvider 實際上是 ContentProvider 的一個子類,它的作用也比較明顯,file://Uri 不給用,那麼換個 Uri 為 content:// 來替代。

接下來看下如何使用:

1、定義 FileProvider
我們先在 AndroidManifest 中進行註冊

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

 

2、指定可分享的檔案路徑

FileProvider 只能為指定的目錄中的檔案生成內容 URI。要指定目錄,就必須使用元素的子元素在 XML 中指定其儲存區域和路徑。

我們先建立一個名為 res/xml/file_paths_public.xml 的新檔案

<paths>
    
    <external-path
        name="my_images"
        path="Pictures/" />

    
    <root-path
        name="root_path"
        path="." />
paths>

 

在 paths 節點內部支援以下幾個子節點,分別為:

  • root-path:裝置的根目錄 new File(“/”)

  • files-path:context.getFileDir()

  • cache-path:context.getCacheDir()

  • external-path:Environment.getExternalStorageDirectory()

  • external-files-path:context.getExternalFilesDirs()

  • external-cache-path:getExternalCacheDirs()

程式碼中的常見用法:

Intent intent = new Intent("android.intent.action.VIEW");
intent.addCategory("android.intent.category.DEFAULT");
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); // FileProvider方式必須加這個臨時許可權
Uri uri = FileProvider.getUriForFile(mContext, "com.hccf.fileprovider", file);
intent.setDataAndType(uri, "application/pdf");
mContext.startActivity(intent);

還有一種用法是: 使用Context 的 grantUriPermission() 方法和revokeUriPermission(); 這種比較少用。
至此,FileProvider的介紹就差不多結束了。

  • V2簽名

APK signature scheme v2:
Android 7.0 引入一項新的應用簽名方案 APK Signature Scheme v2,它能提供更快的應用安裝時間和更多針對未授權 APK 檔案更改的保護。在預設情況下,Android Studio 2.2 和 Android Plugin for Gradle 2.2 會使用 APK Signature Scheme v2 和傳統簽名方案來簽署您的應用。

使用Android Studio 自帶的打包工具的話,只有勾選了了v2簽名的方式,app才能在標的版本24及以上的7.0系統手機安裝。
還有一些其他的比較少遇到的,就不做贅述了,參考文章:
https://blog.csdn.net/qq_17766199/article/details/77404712

Android6.0即API23適配

  • 執行時許可權

Android6.0推出的重大更新,收緊許可權,提高應用安全。具體介紹參考文章即可:
https://blog.csdn.net/qq_17766199/article/details/77404712
一般推薦使用一些第三方框架,他們已經幫你做好了大部分機型的適配問題。
本人使用的RxPermissions
使用方式:

            // 獲取許可權
            RxPermissions rxPermissions = new RxPermissions(getActivity());
            rxPermissions.request(Manifest.permission.READ_EXTERNAL_STORAGE,
                    Manifest.permission.WRITE_EXTERNAL_STORAGE)
                    .subscribe(new Observer() {
                        @Override
                        public void onSubscribe(Disposable d) {

                        }

                        @Override
                        public void onNext(Boolean aBoolean) {
                            if (aBoolean){
                                // 許可權獲取成功 開始下載
                            }
                        }

                        @Override
                        public void onError(Throwable e) {
                            // 獲取許可權失敗,跳轉設定頁面
                            new PermissionPageUtils(getActivity()).jumpPermissionPage();
                            ToastUtils.showLongBottom("獲取許可權失敗,請檢查是否開啟所需許可權");
                        }

                        @Override
                        public void onComplete() {

                        }
                    });

Android5.0即API21~22適配

  • 未完待續

已同步到看一看
贊(0)

分享創造快樂