前言今天分享的面試題是: Android在版本迭代中,總會(huì)進(jìn)行很多改動(dòng),那么你熟知各版本都改動(dòng)了什么內(nèi)容?又要怎么適配呢? Android4.4
Android5.0
Android6.0
如果你的應(yīng)用使用到了危險(xiǎn)權(quán)限,比如在運(yùn)行時(shí)進(jìn)行檢查和請(qǐng)求權(quán)限。
Android 6.0 版移除了對(duì) android {useLibrary 'org.apache.http.legacy'} 有的小伙伴可能不熟悉這是啥,簡(jiǎn)單說(shuō)下:
所以說(shuō)白了,其實(shí)就是一個(gè)請(qǐng)求網(wǎng)絡(luò)的項(xiàng)目框架。 Android 7.0
這一點(diǎn)其實(shí)就是限制了在應(yīng)用間共享文件,如果需要在應(yīng)用間共享,需要授予要訪問(wèn)的URI臨時(shí)訪問(wèn)權(quán)限,我們要做的就是注冊(cè) 1)聲明FileProvider。 <provider android:name="android.support.v4.content.FileProvider" android:authorities="app的包名.fileProvider" android:grantUriPermissions="true" android:exported="false"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider> <!--androidx版本類(lèi)路徑為:androidx.core.content.FileProvider--> 2)編寫(xiě)xml文件,確定可訪問(wèn)的目錄 <paths xmlns:android="http://schemas./apk/res/android"> //代表設(shè)備的根目錄new File("/"); <root-path name="root" path="." /> //context.getFilesDir() <files-path name="files" path="." /> //context.getCacheDir() <cache-path name="cache" path="." /> //Environment.getExternalStorageDirectory() <external-path name="external" path="." /> //context.getExternalFilesDirs() <external-files-path name="name" path="path" /> //getExternalCacheDirs() <external-cache-path name="name" path="path" /> </paths> 3)使用FileProvider if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { Uri uri = FileProvider.getUriForFile(CameraActivity.this, "app的包名.fileProvider", photoFile); } else { Uri uri = Uri.fromFile(photoFile); } Android8.0
在 也就是說(shuō),以前你申請(qǐng)了
Android 8.0 對(duì)于通知修改了很多,比如通知渠道、通知標(biāo)志、通知超時(shí)、背景顏色。其中比較重要的就是通知渠道,其允許您為要顯示的每種通知類(lèi)型創(chuàng)建用戶(hù)可自定義的渠道。 這樣的好處就是對(duì)于某個(gè)應(yīng)用可以把權(quán)限分成很多類(lèi),用戶(hù)來(lái)控制是否顯示哪些類(lèi)別的通知。而開(kāi)發(fā)者要做的就是必須設(shè)置這個(gè)渠道id,否則通知可能會(huì)失效。 private void createNotificationChannel() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); //分組(可選) //groupId要唯一 String groupId = "group_001"; NotificationChannelGroup group = new NotificationChannelGroup(groupId, "廣告"); //創(chuàng)建group notificationManager.createNotificationChannelGroup(group); //channelId要唯一 String channelId = "channel_001"; NotificationChannel adChannel = new NotificationChannel(channelId, "推廣信息", NotificationManager.IMPORTANCE_DEFAULT); //補(bǔ)充channel的含義(可選) adChannel.setDescription("推廣信息"); //將渠道添加進(jìn)組(先創(chuàng)建組才能添加) adChannel.setGroup(groupId); //創(chuàng)建channel notificationManager.createNotificationChannel(adChannel); //創(chuàng)建通知時(shí),標(biāo)記你的渠道id Notification notification = new Notification.Builder(MainActivity.this, channelId) .setSmallIcon(R.mipmap.ic_launcher) .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher)) .setContentTitle("一條新通知") .setContentText("這是一條測(cè)試消息") .setAutoCancel(true) .build(); notificationManager.notify(1, notification); } }
Android8.0以上必須使用新的窗口類(lèi)型( if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { mWindowParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY }else { mWindowParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT }
Android 8.0去除了“允許未知來(lái)源”選項(xiàng),所以如果我們的App有安裝App的功能(檢查更新之類(lèi)的),那么會(huì)無(wú)法正常安裝。 <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/> private void installAPK(){ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { boolean hasInstallPermission = getPackageManager().canRequestPackageInstalls(); if (hasInstallPermission) { //安裝應(yīng)用 } else { //跳轉(zhuǎn)至“安裝未知應(yīng)用”權(quán)限界面,引導(dǎo)用戶(hù)開(kāi)啟權(quán)限 Uri selfPackageUri = Uri.parse("package:" + this.getPackageName()); Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, selfPackageUri); startActivityForResult(intent, 100); } }else { //安裝應(yīng)用 } } //接收“安裝未知應(yīng)用”權(quán)限的開(kāi)啟結(jié)果 @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == 100) { installAPK(); } }
只有全屏不透明的 我們的處理辦法就是要么去掉設(shè)置方向的代碼,要么舍棄透明效果。 Android9.0
<application android:networkSecurityConfig="@xml/network_security_config"> <network-security-config> <base-config cleartextTrafficPermitted="true" /> </network-security-config> <!--或者在AndroidManifest.xml中配置: android:usesCleartextTraffic="true" -->
在6.0中取消了對(duì) <uses-library android:name="org.apache.http.legacy" android:required="false"/>
Android 9.0 要求創(chuàng)建一個(gè)前臺(tái)服務(wù)需要請(qǐng)求 FOREGROUND_SERVICE 權(quán)限,否則系統(tǒng)會(huì)引發(fā) SecurityException。 <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { startForegroundService(intentService); } else { startService(intentService); }
在9.0 中,不能直接非 Activity 環(huán)境中(比如Service,Application)啟動(dòng) Activity,否則會(huì)崩潰報(bào)錯(cuò),解決辦法就是加上 Intent intent = new Intent(this, TestActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); Android10
Android10中默認(rèn)開(kāi)啟了分區(qū)存儲(chǔ),也就是沙盒模式。應(yīng)用只能看到本應(yīng)用專(zhuān)有的目錄(通過(guò) 如果需要關(guān)閉這個(gè)功能可以配置: android:requestLegacyExternalStorage="true" 分區(qū)存儲(chǔ)下,訪問(wèn)文件的方法: 1)應(yīng)用專(zhuān)屬目錄 //分區(qū)存儲(chǔ)空間 val file = File(context.filesDir, filename) //應(yīng)用專(zhuān)屬外部存儲(chǔ)空間 val appSpecificExternalDir = File(context.getExternalFilesDir(), filename) 2)訪問(wèn)公共媒體目錄文件 val cursor = contentResolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, null, null, "${MediaStore.MediaColumns.DATE_ADDED} desc") if (cursor != null) { while (cursor.moveToNext()) { val id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns._ID)) val uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id) println("image uri is $uri") } cursor.close() } 3)SAF(存儲(chǔ)訪問(wèn)框架--Storage Access Framework) val intent = Intent(Intent.ACTION_OPEN_DOCUMENT) intent.addCategory(Intent.CATEGORY_OPENABLE) intent.type = "image/*" startActivityForResult(intent, 100) @RequiresApi(Build.VERSION_CODES.KITKAT) override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (data == null || resultCode != Activity.RESULT_OK) return if (requestCode == 100) { val uri = data.data println("image uri is $uri") } }
從Android10開(kāi)始普通應(yīng)用不再允許請(qǐng)求權(quán)限android.permission.READ_PHONE_STATE。而且,無(wú)論你的App是否適配過(guò)Android Q(既targetSdkVersion是否大于等于29),均無(wú)法再獲取到設(shè)備IMEI等設(shè)備信息。 如果Android10以下設(shè)備獲取設(shè)備IMEI等信息,可以配置最大sdk版本: <uses-permission android:name="android.permission.READ_PHONE_STATE" android:maxSdkVersion="28"/> Android 11
沒(méi)錯(cuò),Android11強(qiáng)制執(zhí)行分區(qū)存儲(chǔ),也就是沙盒模式。這次真的沒(méi)有關(guān)閉功能了,離Android11出來(lái)也有一段時(shí)間了,還是抓緊適配把。
改動(dòng)了兩個(gè)API:getLine1Number()和 getMsisdn() ,需要加上READ_PHONE_NUMBERS權(quán)限
你一定很奇怪,為什么 哈哈,因?yàn)楦膭?dòng)還是挺多的,所以給你推薦文章— 參考https:///post/6898176468661059597 拜拜
|
|
來(lái)自: 丹楓無(wú)跡 > 《待分類(lèi)》