Android適配全面總結(jié)(二)----版本適配

版權(quán)聲明:本文為博主原創(chuàng)文章(部分引用他人博文女阀,已加上引用說明)译打,未經(jīng)博主允許不得轉(zhuǎn)載智哀。http://www.reibang.com/p/49fa8ebc0105

轉(zhuǎn)載請標明出處:
http://www.reibang.com/p/49fa8ebc0105
本文出自 AWeiLoveAndroid的博客


上一篇文章講了 屏幕適配 http://www.reibang.com/p/7aa34434ad4d
這一篇文章講一下 版本適配 http://www.reibang.com/p/49fa8ebc0105
下一篇文章講一下 ROM適配 http://www.reibang.com/p/f9c67a4b908e

在我們的開發(fā)中,會對不同安卓版本做適配贸呢,比如我之前做過的項目中最低兼容到4.4镰烧,最高兼容是最新的系統(tǒng)7.1,由于不同版本的系統(tǒng)中部分API版本也不同楞陷,我就要對這些API做特殊處理怔鳖。新的平臺有一些API不能使用舊的API,舊的平臺也使用不了新的API固蛾。所以這就要考驗我們開發(fā)人員的能力了结执。我這里簡單給出幾點我開發(fā)中使用過的一些方式,僅供參考:

一艾凯、同一個api在不同版本都存在献幔,只是api的一些接口方法有變更。

這種情況是最好處理的览芳,只要對版本號做判斷斜姥,對應的系統(tǒng)版本用相應的api方法就好了。為了好維護沧竟,建議做一個簡單的封裝铸敏。

舉例說明如下:

比如Notification在不同版本的兼容,舉例如下:

首先打開谷歌官方文檔悟泵,看看文檔里面的一些說明:

Notification官方文檔

1.Notification這個類是added in API level 1杈笔,一直都有,只是具體某些方法有變更糕非。繼續(xù)往下看蒙具。

2.這個類有個說明,意思是Notification.Builder是新增的一個內(nèi)部類朽肥,用它創(chuàng)建通知更方便禁筏。接著往下看。

A class that represents how a persistent notification is to
be presented to the user using the NotificationManager.

The Notification.Builder has been added to make it easier
to construct Notifications.

3.Public constructors公共的構(gòu)造方法衡招,其中有3個參數(shù)的這個在api 11過時篱昔,它被Notification.Builder替代了。

Notification(int icon, CharSequence tickerText, long when)

This constructor was deprecated in API level 11. 
Use Notification.Builder instead.

4.常量

  • EXTRA_LARGE_ICON This constant was deprecated in API level 26. Use getLargeIcon(), which supports a wider variety of icon sources.(在API級別26中已棄用始腾。使用getLargeIcon()州刽,它支持更多種圖標源。)

  • EXTRA_SMALL_ICON This constant was deprecated in API level 26. Use getSmallIcon(), which supports a wider variety of icon sources.(在API級別26中已棄用浪箭。使用getSmallIcon()穗椅,它支持更多種圖標源。)

  • FLAG_HIGH_PRIORITY This constant was deprecated in API level 16. Use priority with a positive value.(在api16被棄用奶栖,請使用正數(shù)priority值替代)

  • FLAG_SHOW_LIGHTS This constant was deprecated in API level 26. use shouldShowLights().(在API級別26中已棄用匹表。請使用 shouldShowLights() 替代)

  • PRIORITY_DEFAULT This constant was deprecated in API level 26. use IMPORTANCE_DEFAULT instead.(在API級別26中已棄用门坷。請使用 IMPORTANCE_DEFAULT 替代)

  • PRIORITY_HIGH This constant was deprecated in API level 26. use IMPORTANCE_HIGH instead.(在API級別26中已棄用。請使用 IMPORTANCE_HIGH 替代)

  • PRIORITY_LOW This constant was deprecated in API level 26. use IMPORTANCE_LOW instead.(在API級別26中已棄用桑孩。請使用 IMPORTANCE_LOW 替代)

  • PRIORITY_MAX This constant was deprecated in API level 26. use IMPORTANCE_HIGH instead.(在API級別26中已棄用拜鹤。請使用 IMPORTANCE_HIGH 替代)

  • PRIORITY_MIN This constant was deprecated in API level 26. use IMPORTANCE_MIN instead.(在API級別26中已棄用。請使用 IMPORTANCE_MIN 替代)

  • STREAM_DEFAULT This constant was deprecated in API level 21. Use getAudioAttributes() instead.(在API級別21中已棄用流椒。請使用 getAudioAttributes() 替代)

5.字段Fields

  • audioAttributes 在api 26棄用. 使用 getAudioAttributes() 替代.

  • audioStreamType 在api 21棄用. 使用 audioAttributes 替代.

  • defaults 此字段在API 26棄用敏簿。使用getSound()shouldShowLights()shouldVibrate()

  • icon 此字段已在API級別26中棄用宣虾。使用setSmallIcon(Icon)替代惯裕。

  • largeIcon This field was deprecated in API level 23. Use `setLargeIcon(Icon) instead.

  • ledARGB This field was deprecated in API level 26. use `shouldShowLights().

  • ledOffMS This field was deprecated in API level 26. use `shouldShowLights().

  • ledOnMS This field was deprecated in API level 26. use shouldShowLights().

  • priority This field was deprecated in API level 26. use getImportance() instead.

  • sound This field was deprecated in API level 26. use getSound() instead.

  • vibrate This field was deprecated in API level 26. use getVibrationPattern().


二、Android6.0的動態(tài)權(quán)限介紹

因為Android6.0(API23)開始需要動態(tài)申請權(quán)限绣硝,需要手動申請的權(quán)限有8組(短信蜻势、電話、聯(lián)系人鹉胖、存儲握玛、位置、麥克風甫菠、日歷挠铲、相機),共24個寂诱,如下所示:

所屬權(quán)限組 權(quán)限
短信 SEND_SMS
短信 RECEIVE_SMS
短信 READ_SMS
短信 RECEIVE_WAP_PUSH
短信 RECEIVE_MMS
電話 READ_PHONE_STATE
電話 CALL_PHONE
電話 READ_CALL_LOG
電話 WRITE_CALL_LOG
電話 ADD_VOICEMAIL
電話 USE_SIP
電話 PROCESS_OUTGOING_CALLS
聯(lián)系人 READ_CONTACTS
聯(lián)系人 WRITE_CONTACTS
聯(lián)系人 GET_ACCOUNTS
存儲 READ_EXTERNAL_STORAGE
存儲 WRITE_EXTERNAL_STORAGE
位置 ACCESS_FINE_LOCATION
位置 ACCESS_COARSE_LOCATION
麥克風 RECORD_AUDIO
日歷 READ_CALENDAR
日歷 WRITE_CALENDAR
相機 CAMERA
傳感器 BODY_SENSORS

注意:如果應用程序請求在AndroidManifest中列出的危險權(quán)限拂苹,并且應用程序已經(jīng)在同一權(quán)限組中具有另一個危險權(quán)限,系統(tǒng)會立即授予權(quán)限痰洒,而不會與用戶進行任何交互瓢棒。
例如,如果一個應用程序先前已經(jīng)請求并被授予READ_CONTACTS權(quán)限丘喻,然后它請求WRITE_CONTACTS(同屬于聯(lián)系人一組)脯宿,系統(tǒng)會立即授予該權(quán)限,不會再彈出權(quán)限授予詢問的對話框泉粉。


三连霉、Android6.0如何申請動態(tài)權(quán)限

開發(fā)中經(jīng)常會遇到拍照的權(quán)限申請,這里就講一下如何動態(tài)設置拍照權(quán)限:

//別忘記在清單文件也加上CAMERA權(quán)限
//<uses-permission android:name="android.permission.CAMERA" />

// 定義識別碼
public static final int CAMERA_OK = 1;

//動態(tài)申請拍照權(quán)限
if (Build.VERSION.SDK_INT>22){
   if (ContextCompat.checkSelfPermission(this,Manifest.permission.CAMERA)
        != PackageManager.PERMISSION_GRANTED){
           //先判斷有沒有權(quán)限 搀继,沒有就在這里進行權(quán)限的申請
           requestPermissions(new String[]{Manifest.permission.CAMERA}, CAMERA_OK);       
    }else {
            //說明已經(jīng)獲取到攝像頭權(quán)限了,可以去選擇照片或者拍照了翠语。
            toSelectPhotoOrOpenCamera();
    }
}else {
      //這個說明系統(tǒng)版本在6.0之下叽躯,不需要動態(tài)獲取權(quán)限,直接去選擇照片或者拍照肌括。
      toSelectPhotoOrOpenCamera();
}

//在Activity中重寫權(quán)限獲取方法:

/**
* 權(quán)限操作結(jié)果處理
*/
@Override
public void onRequestPermissionsResult(int requestCode,
                       String[] permissions, int[] grantResults) {
    switch (requestCode) {
        case CAMERA_OK: 
            if (grantResults.length > 0 && grantResults[0]
                         == PackageManager.PERMISSION_GRANTED) {
                 //用戶已授權(quán)
                toSelectPhotoOrOpenCamera();
            } else {
                //用戶拒絕權(quán)限
                ToastUtils.show(this, 
                    "缺少相機權(quán)限点骑,暫時無法提供掃描功能,請嘗試在設置中打開相機權(quán)限!", 
                    Toast.LENGTH_LONG);
            }
            break;
        }
    }
}

四酣难、Android7.0對文件權(quán)限進一步升級,提出了新的類FileProvider來獲取文件黑滴。所以適配的時候一定要注意這一點api的變化憨募。

FileProviderContentProvider的子類,把原來文件共享的 file://uri 換成了 content://uri 袁辈。一個Uri允許你獲取臨時權(quán)限去讀寫文件菜谣,當使用含有Uri的Intent,可以使用Intent.setFlags來添加臨時權(quán)限晚缩。

下面來看看調(diào)用系統(tǒng)相機拍攝照片有如何變化尾膊,大致步驟如下所示

(一)在manifest中添加Provider

<manifest>
    ...
    <application>
        ...
        <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="com.lzw.demo.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            ...
        </provider>
        ...
    </application>
</manifest>

(二)配置你要獲取的文件所在的文件夾 --> 創(chuàng)建一個xml文件,比如file_demo.xml荞彼,文件內(nèi)容如下:

<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <files-path name="my_images" path="images/"/>
    ...
</paths>

路徑說明:

<files-path name="name" path="path/" />   
   <!--等同于Context.getFilesDir()下面的path文件夾的所有文件--> 

<cache-path name="name" path="path/" />  
   <!--等同于Context.getCacheDir()下面的path文件夾--> 

<external-path name="name" path="path/" /> 
   <!--等同于Environment.getExternalStorageDirectory()下面的path文件夾--> 

<external-files-path name="name" path="path/" /> 
   <!--等同于 Context#getExternalFilesDir(String)下面子文件path文件夾--> 

<external-cache-path name="name" path="path/" /> 
   <!--相當于 Context.getExternalCacheDir()下邊的path文件夾--> 

(三)添加路徑信息到provier

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

(四)現(xiàn)在可以去拍照了冈敛。(由于Android6.0開始要動態(tài)申請權(quán)限,所以別忘了鸣皂,這里就不寫了抓谴,主要講FileProvider的使用)

//適配7.0的fileprovider,imgfile是圖片文件路徑
public void TakePhotoAdaption(File imgFile){
    Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    //適配android7.0 手機拍照取uri的處理
    if(Build.VERSION.SDK_INT<24){
        //7.0如果用會Uri.fromFile(XXX)會閃退寞缝,所以這里要特別做一個判斷癌压。
        //imgfile是圖片文件路徑
        uri = Uri.fromFile(imgFile);
        cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
    }else{
        //7.0+使用FileProvider.getUriForFile這個api
        uri=FileProvider.getUriForFile(DemoActivity.this,
                "com.lzw.demo.fileprovider",imgFile);
        cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
        //添加這一句表示對目標應用臨時授權(quán)該Uri所代表的文件
        cameraIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION );
    }
    startActivityForResult(cameraIntent, FLAG_CHOOSE_CAMERA);
}

想看到拍照、選擇照片第租、裁剪等完整流程的描述措拇,可以參考這篇博客 解決安卓7.0拍照,相冊選擇崩潰的問題(包括壓縮圖片在內(nèi))


五慎宾、關(guān)于Android7.0相機閃退以及相冊獲取不到圖片問題

  • 1丐吓、沒有動態(tài)申請權(quán)限,按照上述思路去做就好了趟据。
  • 2券犁、華為手機的一些特殊處理方式,詳情參見 ROM適配 http://www.reibang.com/p/f9c67a4b908e

六汹碱、Android 8.0適配報錯:Only fullscreen opaque activities can request orientation解決方案:

出現(xiàn)的原因:絕大多數(shù)都是因為我們?yōu)榱颂岣哂脩趔w驗粘衬,手動取消App啟動白屏或者黑屏的時候,將Splash界面設為了透明咳促,然后這個時候又設置了方向為垂直稚新,從而導致了這個問題。

解決方案:

  • 1.找到你設置透明的Activity跪腹,然后在他的theme中將android:windowIsTranslucent改為false

      <item name="android:windowIsTranslucent">false</item>
    
  • 2.再加入下面這行代碼就搞定了褂删。

      <item name="android:windowDisablePreview">true</item>
    

這個坑來自于博客: http://www.reibang.com/p/d0d907754603


七、Android8.0版本更新相關(guān)api適配

  • 創(chuàng)建通知渠道
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
            NotificationChannel mChannel = new NotificationChannel("channel_01",
                    "消息推送", NotificationManager.IMPORTANCE_DEFAULT);
            manager.createNotificationChannel(mChannel);
        }
  • 創(chuàng)建Notification
Context context = DJApplication.getInstance();
        Notification.Builder builder = new Notification.Builder(context);
        builder.setTicker("開始下載");
        builder.setSmallIcon(R.mipmap.ic_launcher);
        builder.setLargeIcon(BitmapFactory.decodeResource(DJApplication.getInstance().getResources(), 
            R.mipmap.ic_launcher));
        builder.setAutoCancel(true);
        PendingIntent pIntent = PendingIntent.getActivity(context, 0, new Intent(), PendingIntent.FLAG_UPDATE_CURRENT);
        builder.setContentTitle("下載中");
        builder.setContentIntent(pIntent);
        builder.setContentText(text);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            builder.setChannelId("channel_01");//設置有效的通知渠道 ID冲茸,這個ID要和之前創(chuàng)建時候的Channel_ID相同
        }
        manager.notify(1,  builder.build());
  • 安裝apk權(quán)限

在 Android 8.0 中屯阀,安裝未知應用權(quán)限提高了安裝未知來源應用時的安全性缅帘。此權(quán)限與其他運行時權(quán)限一樣,會與應用綁定难衰,在安裝時進行提示钦无,確保用戶授予使用安裝來源的權(quán)限后,此權(quán)限才會提示用戶安裝應用盖袭。在運行 Android 8.0 或更高版本的設備上使用此權(quán)限時失暂,惡意下載程序?qū)o法騙取用戶安裝未獲得預先授權(quán)的應用,所以我們需要加入安裝apk文件的權(quán)限苍凛。

<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末趣席,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子醇蝴,更是在濱河造成了極大的恐慌宣肚,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,273評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件悠栓,死亡現(xiàn)場離奇詭異霉涨,居然都是意外死亡,警方通過查閱死者的電腦和手機惭适,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評論 3 398
  • 文/潘曉璐 我一進店門笙瑟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人癞志,你說我怎么就攤上這事往枷。” “怎么了凄杯?”我有些...
    開封第一講書人閱讀 167,709評論 0 360
  • 文/不壞的土叔 我叫張陵错洁,是天一觀的道長。 經(jīng)常有香客問我戒突,道長屯碴,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,520評論 1 296
  • 正文 為了忘掉前任膊存,我火速辦了婚禮导而,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘隔崎。我一直安慰自己今艺,他們只是感情好,可當我...
    茶點故事閱讀 68,515評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般歪脏。 火紅的嫁衣襯著肌膚如雪舟扎。 梳的紋絲不亂的頭發(fā)上遥巴,一...
    開封第一講書人閱讀 52,158評論 1 308
  • 那天,我揣著相機與錄音享幽,去河邊找鬼铲掐。 笑死,一個胖子當著我的面吹牛值桩,可吹牛的內(nèi)容都是我干的摆霉。 我是一名探鬼主播,決...
    沈念sama閱讀 40,755評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼奔坟,長吁一口氣:“原來是場噩夢啊……” “哼携栋!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起咳秉,我...
    開封第一講書人閱讀 39,660評論 0 276
  • 序言:老撾萬榮一對情侶失蹤婉支,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后澜建,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體向挖,經(jīng)...
    沈念sama閱讀 46,203評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,287評論 3 340
  • 正文 我和宋清朗相戀三年炕舵,在試婚紗的時候發(fā)現(xiàn)自己被綠了何之。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,427評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡咽筋,死狀恐怖溶推,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情奸攻,我是刑警寧澤蒜危,帶...
    沈念sama閱讀 36,122評論 5 349
  • 正文 年R本政府宣布,位于F島的核電站舞箍,受9級特大地震影響舰褪,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜疏橄,卻給世界環(huán)境...
    茶點故事閱讀 41,801評論 3 333
  • 文/蒙蒙 一占拍、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧捎迫,春花似錦晃酒、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至彰导,卻和暖如春蛔翅,著一層夾襖步出監(jiān)牢的瞬間敲茄,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評論 1 272
  • 我被黑心中介騙來泰國打工山析, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留堰燎,地道東北人。 一個月前我還...
    沈念sama閱讀 48,808評論 3 376
  • 正文 我出身青樓笋轨,卻偏偏與公主長得像秆剪,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子爵政,可洞房花燭夜當晚...
    茶點故事閱讀 45,440評論 2 359

推薦閱讀更多精彩內(nèi)容