day 10-11 面试题:Android6.0-Android 7.0适配

面试题:

1. Android 6.0适配     
2. Android 7.0适配

1. Android 6.0适配

1.1 HttpClient不支持问题

在Android 6.0以上,HttpClient被google从系统库中移除,有两种方式可以处理

  1. module下的gradle文件中的添加声明

    useLibrary ‘org.apache.http.legacy’

  2. 添加HttpClient依赖

    1. 百度搜索 maven,找一个maven库
    2. 搜索HttpClient,找到apache的HttpClient库
    3. 下载jar或者引入依赖即可
1.2 动态权限申请

targetSdkVersion 改为23及以上之后,所有需要手动授予的权限如果不申请,会闪退。

  1. 目前国内安卓绿色联盟要求必须把targetSdkVersion提高到26,否则不予上架,所以,把targetSdkVersion限制在23以下的方案已废弃。

  2. 适配动态权限

    自己对该功能进行封装一下,方便调用。

    1. 判断是否是Android 6.0以上

       Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
      
    2. 判断是否具有对应的权限

       context.checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED
      
    3. 如果没有权限,调用权限申请方法去申请

       activity.requestPermissions(permissions, requestCode)
      
    4. 在Activity的onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)方法中对操作结果进行判断,如果通过则继续执行原有逻辑,如果没有则弹框提示明确信息让用户去设置界面手动授予。

2. Android 7.0适配

2.1 使用FileProvider进行应用间共享文件

不做FileProvider适配的话,在拍照、apk安装等场景下,因为调用了file://格式的Uri读取文件,会抛出FileUriExposedException.

适配步骤:

  1. AndroidManifest.xml文件中声明provider

     <!--FileProvider的支持-->
     <provider
         android:name="android.support.v4.content.FileProvider"
         android:authorities="${applicationId}.android7.fileprovider"
         android:exported="false"
         android:grantUriPermissions="true">
         <meta-data
             android:name="android.support.FILE_PROVIDER_PATHS"
             android:resource="@xml/file_paths" />
     </provider>
    
  2. 编写file_paths.xml文件,例子中放在xml文件夹下

     <?xml version="1.0" encoding="utf-8"?>
     <paths xmlns:android="http://schemas.android.com/apk/res/android">
     <!--
         <root-path/> 代表设备的根目录new File("/");
         <files-path/> 代表context.getFilesDir()
         <cache-path/> 代表context.getCacheDir()
         <external-path/> 代表Environment.getExternalStorageDirectory()
         <external-files-path>代表context.getExternalFilesDirs()
         <external-cache-path>代表getExternalCacheDirs()
         -->
     
         <root-path name="root" path=""/>
         <files-path name="files" path="file" />
         <cache-path name="cache" path="cache" />
         <external-path name="external" path="SD" />
         <external-files-path name="name" path="SD_file" />
         <external-cache-path name="name" path="SD_cache" />
     </paths>
    
  3. 添加Utils方法,适配Uri的获取

     public static Uri getUriForFile(Context context, File file) {
         Uri fileUri = null;
         if (Build.VERSION.SDK_INT >= 24) {
             fileUri = getUriForFile24(context, file);
         } else {
             fileUri = Uri.fromFile(file);
         }
         return fileUri;
     }
    
     public static Uri getUriForFile24(Context context, File file) {
         Uri fileUri = android.support.v4.content.FileProvider.getUriForFile(context,
                 context.getPackageName() + ".android7.fileprovider",
                 file);
         return fileUri;
     }
    
  4. 调用处修改为封装的Utils方法

     getUriForFile(context, file)
    
2.2 APK signature schema v2

无网环境下写的文档,所以不附图了

在打Release包时:工具栏 Build -> Generate Signed APK ->输入密码 ->Signature Versions。
此处选项V!和V2都要选上

只勾选V2,7.0以下会显示未安装,7.0以上会使用V2的安全验证方式。

2.3 拒绝webview注入

我的项目以前的js注入是,注册了js后又注入了一段js脚本,在targetSdkVersion升级到25以后,完全失效。

原代码:

private void initGPS() {
	mJsGPS = new JsGPS(mWebView);
	mWebView.addJavascriptInterface(mJsGPS, "EMPGeolocation");
	registerGPS();
}

private void registerGPS() {
	// 嵌套一层方法,防止传来的回调函数不是字符串
	String gpsJStr = "function Geolocation(){};".concat("Geolocation.prototype.getCurrentLocation = function(callback, accuracy)").concat("{")
			.concat(" EMPGeolocation.getCurrentLocation(getFuncName(callback), accuracy);").concat("};").concat("var geolocation = new Geolocation();");
	mWebView.loadUrl("javascript:".concat(gpsJStr));
}

解决方案:

  1. 修改js方案为jsbridge方式,复用window.prompt(有心的话可以百度搜索一下,使用还是很方便的)
  2. 将原来需要在客户端注入的js逻辑抽出来,让h5页面提前加载
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
package com.example.tigongzhe; import android.R.integer; import android.content.ContentProvider; import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; import android.content.UriMatcher; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase.CursorFactory; import android.database.sqlite.SQLiteOpenHelper; import android.net.Uri; import android.provider.SyncStateContract.Helpers; import android.text.Selection; import android.util.Log; public class provider extends ContentProvider { private MyOpenHelper myOpenHelper; private SQLiteDatabase sqLiteDatabase; private static final UriMatcher URI_MATCHER=new UriMatcher(UriMatcher.NO_MATCH); private final String TAG="provider"; private static final String authority="com.example.tigongzhe.provider"; static { URI_MATCHER.addURI(authority, "contacter", 1); URI_MATCHER.addURI(authority, "contacter/#", 2); } private static final String _id="id"; private static final String name="name"; private static final String num="num"; @Override public boolean onCreate() { // TODO Auto-generated method stub myOpenHelper=new MyOpenHelper(getContext(), DB_Name, null, version_1); return true; } @Override public String getType(Uri uri) { // TODO Auto-generated method stub int flag=URI_MATCHER.match(uri); switch (flag) { case 2: return "vnd.android.cursor.item/contacter"; case 1: return "vnd.android.dir.item/contacter"; default: throw new IllegalArgumentException("异常参数"); } } @Override public Uri insert(Uri uri, ContentValues values) { // TODO Auto-generated method stub sqLiteDatabase=myOpenHelper.getWritableDatabase(); int flag=URI_MATCHER.match(uri); switch (flag) { case 1: sqLiteDatabase.insert(Table_Name, name, values); break; case 2: long id=sqLiteDatabase.insert(Table_Name, name, values); ContentUris.withAppendedId(uri, id); default: break; } return uri; } @Override public Cursor query(Uri uri, String[] arg1, String arg2, String[] arg3, String arg4) { // TODO Auto-generated method stub Cursor cursor; sqLiteDatabase=myOpenHelper.getReadableDatabase(); int flag=URI_MATCHER.match(uri); switch (flag) { case 1: cursor=sqLiteDatabase.query(Table_Name, arg1, arg2, arg3, null, null,arg4); break; case 2: long id=ContentUris.parseId(uri); arg2=(arg2==null||"".equals(arg2.trim()))? _id+"="+id:arg2+"and"+_id+"="+id; cursor=sqLiteDatabase.query(Table_Name, arg1, arg2, arg3, null, null,arg4); default: throw new IllegalArgumentException("参数错误"); } return cursor; } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { // TODO Auto-generated method stub int num=0; sqLiteDatabase=myOpenHelper.getWritableDatabase(); int flag=URI_MATCHER.match(uri); switch (flag) { case 1: num=sqLiteDatabase.update(Table_Name, values,selection, selectionArgs); break; case 2: long id=ContentUris.parseId(uri); selection=(selection==null||"".equals(selection.trim()))? _id+"="+id:selection+"and"+_id+"="+id; num=sqLiteDatabase.update(Table_Name, values,selection, selectionArgs); default: break; } return num; } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { // TODO Auto-generated method stub int num=0; sqLiteDatabase=myOpenHelper.getWritableDatabase(); int flag=URI_MATCHER.match(uri); switch (flag) { case 1: num=sqLiteDatabase.delete(Table_Name, selection, selectionArgs); break; case 2: long id=ContentUris.parseId(uri); selection=(selection==null||"".equals(selection.trim()))?_id+"="+id:selection+"and"+_id+"="+id; num=sqLiteDatabase.delete(Table_Name, selection, selectionArgs); default: throw new IllegalArgumentException("异常参数"); } return num; } private final String DB_Name = "mydb.db"; private final String Table_Name="contacter"; private final int version_1=1; private class MyOpenHelper extends SQLiteOpenHelper { public MyOpenHelper(Context context, String name, CursorFactory factory, int version) { super(context, name, factory, version); } /** * @description 当数据表无连接时创建新的表 */ @Override public void onCreate(SQLiteDatabase db) { String sql = " create table if not exists " + Table_Name + "(id INTEGER PRIMARY KEY AUTOINCREMENT," + "name varchar(64),num varchar(64))"; db.execSQL(sql); } /** * @description 当版本更新时触发的方法 */ @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { String sql = " drop table if exists " + Table_Name; db.execSQL(sql); onCreate(db); } } } +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.tigongzhe" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="18" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="com.example.tigongzhe.MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <provider android:name=".provider" android:authorities="com.example.tigongzhe.provider" android:multiprocess="true" android:exported="true" android:permission="com.example.tigongzhe.permission" ></provider> </application> <permission android:name="com.example.tigongzhe.permission" android:protectionLevel="normal"></permission> </manifest> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++package com.example.tigongzhe; import android.R.integer; import android.content.ContentProvider; import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; import android.content.UriMatcher; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase.CursorFactory; import android.database.sqlite.SQLiteOpenHelper; import android.net.Uri; import android.provider.SyncStateContract.Helpers; import android.text.Selection; import android.util.Log; public class provider extends ContentProvider { private MyOpenHelper myOpenHelper; private SQLiteDatabase sqLiteDatabase; private static final UriMatcher URI_MATCHER=new UriMatcher(UriMatcher.NO_MATCH); private final String TAG="provider"; private static final String authority="com.example.tigongzhe.provider"; static { URI_MATCHER.addURI(authority, "contacter", 1); URI_MATCHER.addURI(authority, "contacter/#", 2); } private static final String _id="id"; private static final String name="name"; private static final String num="num"; @Override public boolean onCreate() { // TODO Auto-generated method stub myOpenHelper=new MyOpenHelper(getContext(), DB_Name, null, version_1); return true; } @Override public String getType(Uri uri) { // TODO Auto-generated method stub int flag=URI_MATCHER.match(uri); switch (flag) { case 2: return "vnd.android.cursor.item/contacter"; case 1: return "vnd.android.dir.item/contacter"; default: throw new IllegalArgumentException("异常参数"); } } @Override public Uri insert(Uri uri, ContentValues values) { // TODO Auto-generated method stub sqLiteDatabase=myOpenHelper.getWritableDatabase(); int flag=URI_MATCHER.match(uri); switch (flag) { case 1: sqLiteDatabase.insert(Table_Name, name, values); break; case 2: long id=sqLiteDatabase.insert(Table_Name, name, values); ContentUris.withAppendedId(uri, id); default: break; } return uri; } @Override public Cursor query(Uri uri, String[] arg1, String arg2, String[] arg3, String arg4) { // TODO Auto-generated method stub Cursor cursor; sqLiteDatabase=myOpenHelper.getReadableDatabase(); int flag=URI_MATCHER.match(uri); switch (flag) { case 1: cursor=sqLiteDatabase.query(Table_Name, arg1, arg2, arg3, null, null,arg4); break; case 2: long id=ContentUris.parseId(uri); arg2=(arg2==null||"".equals(arg2.trim()))? _id+"="+id:arg2+"and"+_id+"="+id; cursor=sqLiteDatabase.query(Table_Name, arg1, arg2, arg3, null, null,arg4); default: throw new IllegalArgumentException("参数错误"); } return cursor; } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { // TODO Auto-generated method stub int num=0; sqLiteDatabase=myOpenHelper.getWritableDatabase(); int flag=URI_MATCHER.match(uri); switch (flag) { case 1: num=sqLiteDatabase.update(Table_Name, values,selection, selectionArgs); break; case 2: long id=ContentUris.parseId(uri); selection=(selection==null||"".equals(selection.trim()))? _id+"="+id:selection+"and"+_id+"="+id; num=sqLiteDatabase.update(Table_Name, values,selection, selectionArgs); default: break; } return num; } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { // TODO Auto-generated method stub int num=0; sqLiteDatabase=myOpenHelper.getWritableDatabase(); int flag=URI_MATCHER.match(uri); switch (flag) { case 1: num=sqLiteDatabase.delete(Table_Name, selection, selectionArgs); break; case 2: long id=ContentUris.parseId(uri); selection=(selection==null||"".equals(selection.trim()))?_id+"="+id:selection+"and"+_id+"="+id; num=sqLiteDatabase.delete(Table_Name, selection, selectionArgs); default: throw new IllegalArgumentException("异常参数"); } return num; } private final String DB_Name = "mydb.db"; private final String Table_Name="contacter"; private final int version_1=1; private class MyOpenHelper extends SQLiteOpenHelper { public MyOpenHelper(Context context, String name, CursorFactory factory, int version) { super(context, name, factory, version); } /** * @description 当数据表无连接时创建新的表 */ @Override public void onCreate(SQLiteDatabase db) { String sql = " create table if not exists " + Table_Name + "(id INTEGER PRIMARY KEY AUTOINCREMENT," + "name varchar(64),num varchar(64))"; db.execSQL(sql); } /** * @description 当版本更新时触发的方法 */ @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { String sql = " drop table if exists " + Table_Name; db.execSQL(sql); onCreate(db); } } }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值