適配Android6.0到8.0詳細過程——小白教程
前言:
由於GooglePlay在2018年11月1日開始上架專案要求targetSdkVersion在26以上,因此只能版本適配了。我的專案版本是22,也就是Android5.1,之前也沒有做過版本適配,只能一邊查資料一邊摸索著搞,如果有不對的地方,或者有更好的解決方案,歡迎聯絡指出!
準備工作:
要適配Android8.0首先要先把AndroidStudio升級到AndroidStudio3.0以上版本。
開啟project.properties,設定
target=android-26
開啟配置檔案build.gradle,修改targetSdkVersion,compileSdkVersion為26以上,更新gradle版本為最新版本,我這裡更新的是gradle:3.2.1
具體如下:
compileSdkVersion 26
targetSdkVersion 26
dependencies {
classpath 'com.android.tools.build:gradle:3.2.1'
}
具體截圖:
buildToolsVersion 會在更新gradle時自動更新成28.0.3 或更新版本。
=========分割線==============
如果有用到程式碼混淆的話,可能回遇到下面這個異常:
更新前程式碼:
buildTypes {
release {
// 是否進行混淆
minifyEnabled false
zipAlignEnabled true
shrinkResources true
// 混淆檔案的位置
proguardFiles getDefaultProguardFile('proguard-project.txt'), 'proguard-project.txt'
buildConfigField "boolean", "LOG_DEBUG", "false"
} debug {
buildConfigField "boolean", "LOG_DEBUG", "true"
}
}
更新後報出異常:
User supplied default proguard base extension name is unsupported
解決:
proguardFile ('TIS-SmarthomeV5.0.3/.../proguard-project.txt')
異常:Removing unused resources requires unused code shrinking to be turned on.
解決:
minifyEnabled true //這裡原本是false改成true
如果不使用程式碼混淆:
// 是否進行混淆
minifyEnabled false
zipAlignEnabled false
shrinkResources false
=======分割線========
編譯,根據錯誤提示,如果之前是用compile的,把compile改成implementation,testCompile改成testImplementation, instrumentTest改成androidTest。
另外如果專案有使用到multidex 突破64k限制解決方案的有可能回報下面這種異常:
解決:
implementation 'com.android.support:multidex:1.0.3'
把依賴改成最新版,我這裡是改成1.0.3,然後就能解決Failed to resolve: multidex這個異常了。
接著下面那個異常是這樣解決的:
修改專案根目錄的那個build.gradle檔案中repositories, 保持google()在第一位置:
allprojects {
repositories {
google()//保持這個放在頂部
mavenCentral()
maven {
url "https://jitpack.io"
}
maven{
url 'https://maven.google.com'
}
jcenter()//保持這個放在底部
}
具體截圖:
接著編譯,
如果出現編譯異常:
Please correct the above warnings first.
看Messages 檢視提示,可以在你的混淆檔案proguard-rules.pro裡面新增下面這句程式碼遮蔽警告:
-ignorewarnings
繼續編譯,有可能會出現v4jar包keyeventcompat不存在的異常:
Error:(30, 31) 錯誤: 找不到符號
符號: 類 KeyEventCompat
位置: 程式包 android.support.v4.view
解決:
KeyEventCompat類被取消了 hasNoModifiers方法已經被KeyEvent實現了
報錯:
if (KeyEventCompat.hasNoModifiers(event)) {
handled = arrowScroll(FOCUS_FORWARD);
} else if (KeyEventCompat.hasModifiers(event, KeyEvent.META_SHIFT_ON)) {
handled = arrowScroll(FOCUS_BACKWARD);
}
改成:
if (event.hasNoModifiers()) {
handled = arrowScroll(FOCUS_FORWARD);
} else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
handled = arrowScroll(FOCUS_BACKWARD);
}
=======================分割線======================
完成以上操作可以成功編譯執行之後,開始先適配6.0的動態許可權:
Android6.0開始,官方對許可權的要求越來越嚴格,所以一些危險許可權需要在程式中動態獲取,讓使用者點選允許許可權才能獲取,普通許可權和以前沒區別,可以直接在清單檔案裡面配置獲取。而危險許可權在清單檔案裡面配置了,如果使用者沒有點選允許一樣是獲取不到的。具體哪些是危險許可權,哪些是普通許可權可以自己在網上查一下,這裡就不詳細說了。
首先在build.gradle中的dependencies裡面新增第三方許可權工具,這裡使用閆振杰封裝的第三方依賴:
dependencies {implementation 'com.yanzhenjie:permission:2.0.0-rc4'}
因為已經在配置檔案中添加了第三方依賴,所以我們可以直接使用別人封裝好的動態獲取許可權的API。一般來說,在開啟程式的主activity那裡我們就要向用戶申請許可權了,在MainActivity的onCreate()方法裡面申請,程式碼如下:
@Override
public void onCreate(Bundle savedInstanceState) {
getWindow().requestFeature(Window.FEATURE_NO_TITLE);//設定無標題
super.onCreate(savedInstanceState);
setContentView(R.layout.main_smartbus);
//寫你自己的初始化佈局…
//獲取外部儲存許可權和地理位置許可權
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { //版本在23及以上
AndPermission.with(this).permission(Permission.READ_EXTERNAL_STORAGE, Permission.WRITE_EXTERNAL_STORAGE,
Permission.ACCESS_FINE_LOCATION, Permission.ACCESS_COARSE_LOCATION).onGranted(new Action() {
@Override
public void onAction(List<String> permissions) {
//TODO
//成功獲取許可權後要做的操作
}
}).onDenied(new Action() {
@Override
public void onAction(List<String> permissions) {
//使用者拒絕許可權,toast提示使用者如果不允許許可權有部分功能將無法使用
Toast.makeText(HomepageActivity.this,
"Rejection may result in some functionality being unavailable.",
Toast.LENGTH_SHORT).show();
}
}).start();
}else{//低於6.0版本的
//TODO
}
}
如果還需要其他危險許可權可以直接在這裡後面新增: AndPermission.with(this).permission(Permission.READ_EXTERNAL_STORAGE, Permission.WRITE_EXTERNAL_STORAGE,
Permission.ACCESS_FINE_LOCATION, Permission.ACCESS_COARSE_LOCATION,
…..
)
而其他危險許可權,例如相機許可權,傳送簡訊許可權,可以在需要用到的地方再申請,因為一開始向用戶申請太多許可權的話,使用者體驗不是那麼好。
例如,可以在開啟相機的回撥那裡動態申請相機許可權:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){//如果當前Android版本是6.0以上的
AndPermission.with(SettingActivity.this).permission(Permission.CAMERA).onGranted(new Action() {
@Override
public void onAction(List<String> permissions) {
//使用者允許許可權,啟用相機
intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT,
Uri.fromFile(new File(getExternalFilesDir("TIS-Smarthome/"), "photo_BgImage.png")));
startActivityForResult(intent, GET_BACKGROUND_PHOTOZOOM);
}
}).onDenied(new Action() {
@Override
public void onAction(List<String> permissions) {
//使用者拒絕許可權,toast提示拒絕許可權將使某些功能無法使用
Toast.makeText(SettingActivity.this,
"Rejection may result in some functionality being unavailable.",
Toast.LENGTH_SHORT).show();
}
}).start();
}else {
//6.0以下的,直接啟動相機
intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT,
Uri.fromFile(new File(getExternalFilesDir("TIS-Smarthome/"), "photo_BgImage.png")));
startActivityForResult(intent, GET_BACKGROUND_PHOTOZOOM);
}
" TIS-Smarthome/"是專案名稱,"photo_BgImage.png"是拍照存放的圖片名稱,也就是外部儲存到你手機哪裡,儲存成什麼名字的圖片。
適配Android7.0:
前面添加了兩個危險許可權之後,如果你的應用有使用相機功能,你會發現在應用中開啟相機就閃退。因為Android官方在7.0對私有目錄訪問進行了限制,這裡我們可以使用FileProvider來解決。(當然你得先申請了相機許可權,不會申請的參照上面的程式碼在啟動相機前申請。)
首先在清單檔案AndroidManifest.xml的application標籤下新增:
<application
android:name="caro.automation.MyApplication"
android:allowBackup="true"
android:hardwareAccelerated="true"
android:hasCode="true"
android:icon="@drawable/tis"
android:label="@string/app_name"
android:usesCleartextTraffic="true"
>
<!--2018.10.16 相機打不開問題-->
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="你的包名.fileprovider"
android:grantUriPermissions="true"
android:exported="false"
>
<meta-data android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
...
</application>
Provider標籤部分,file_paths是我們指定的檔案目錄,所以需要在res資料夾下的xml檔案目錄下新建file_paths.xml,然後編寫程式碼:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<paths>
<external-path path="" name="camera_photos" />
</paths>
</resources>
正常來說這樣已經可以在7.0系統里正常調起相機了,但是有的手機在7.0之後你的APP就算有許可權,給出一個URI之後手機也認為你沒有許可權,這個問題的解決方法是,在MyApplication的onCreate()方法中新增以下程式碼:
/*2018.10.16 相機打不開問題*/
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)//如果當前Android版本大於7.0
{ StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());
}
適配Android8.0:
Android8.0主要是適配通知欄和圖示。我這邊只做了通知欄的適配。
由於我負責的專案是使用第三方個推的,所以適配Android8.0只需要更新個推到最新版GETUI_ANDROID_SDK_2.12.5.0就可以了。先到個推官網下載最新的個推SDKhttp://docs.getui.com/getui/version/
下載完之後根據他的接入文件重新接入一遍SDK就可以,這裡就不詳細描述了,畢竟我怎麼寫都沒有別人的接入文件詳細0.0
更新完個推SDK後,點選建立推送:
選擇目標使用者指定到你的測試機,傳送通知,如果能成功接收到通知就是適配成功了。
完成適配後,使用Androidstudio3.2進行打包,我這裡出現警告fastjson沒有找到相關的類或介面。解決:更新fastjson依賴1.2.51版本,更新完注意把舊版的jar包刪除,不然會報jar包重複,導致打包失敗。
還要注意的是,8.0移除了靜態廣播,所以廣播要改成動態註冊!