Android问题7:在线检测更新包并下载更新遇到的问题

花了两天时间,百度n多文章,终于解决了在线更新的问题,现记录下来,以备后用。

注:以下内容虽然是自己写的,但是参考了大量的网上文章理解后的内容,参考的文章太多,也搞不清楚应该写转载谁的了,就厚颜标为原创,请见谅。

 

整个操作步骤如下:

1. 下载配置文件,解析配置文件内容,获取版本号、描述、apk包文件。

2. 判断版本号是否高于当前正在使用的app的版本号,否则放弃更新操作。

3. 显示提示框,提示用户有新的版本,需要更新吗?

4. 下载apk文件。

5. 完成后,自动运行apk,完成更新。

前面4步操作比较简单,在第5步的时候,卡了两天时间。

1. 下载文件需要写操作权限。

1.1 在app的AndroidManifest.xml文件里,添加申明读写安装权限。

<!-- 以下权限用于读写文件,执行apk包(用于升级安装) -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />

1.2 还需要在代码中申请读写权限。

if (Build.VERSION.SDK_INT >= 23) {
        //android版本大于23(6.0)的,才需要此方法。

        boolean _b1 = false;
        if (_context.checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            //没有读取文件权限
            _b1 = false;
        }

        if (_context.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            //没有写文件权限;
            _b1 = false;
        }
        if (_b1) {
            //已经请求了权限的,不再执行申请操作
            return;
        }

        String[] _ss = {
                Manifest.permission.READ_EXTERNAL_STORAGE,
                Manifest.permission.WRITE_EXTERNAL_STORAGE
        };

        //requestCode,自定义值,用于在Activity的onRequestPermissionsResult方法中识别当前操作是否成功,这里直接使用常量101代替。
        //如果不在Activity中重写onRequestPermissionsResult函数,此值就没啥意义。
        ActivityCompat.requestPermissions(_context, _ss, 101);
        
}

2. 执行apk文件需要申明权限

2.1 在AndroidManifest.xml添加申明:AndroidManifest.xml, 上面操作步骤1.1中已经完成。

2.2 API24以后,执行apk不能使用file://开始的uri,说是不安全,所以要在AndroidManifest.xml添加FileProvider的定义。

<provider
    android:name="androidx.core.content.FileProvider"
    android:authorities="com.trap.fileProvider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/paths"/>
</provider>

注:

1) 在name项目中,旧版本使用的是:android.support.v4.content.FileProvider

2) 在authoritites一项中, com.trap 是app的包名称,后面的fileProvider也可以自定义,后面在引用的时候记得相同就好。

3) 在meta-data一项中,@xml=paths,指向的是res/xml/paths.xml文件,所以我们还需要在res下面创建一个xml文件夹,再添加一个paths.xml文件。

2.3 在res下,添加xml文件夹,并创建paths.xml文件,内容如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <paths>
        <external-path path="." name="download" />
    </paths>
</resources>

2.4 在代码中,申请执行apk的权限。

 

if (Build.VERSION.SDK_INT >= 26) {
    boolean _b1 = _activity.getPackageManager().canRequestPackageInstalls();
    if (!_b1) {
        //requestCode,自定义值,用于在Activity的onRequestPermissionsResult方法中识别当前操作是否成功,这里用103代替,
        //如果不在Activity中重写onRequestPermissionsResult函数,此值就没啥意义。
        ActivityCompat.requestPermissions(_activity, new String[]{Manifest.permission.REQUEST_INSTALL_PACKAGES}, 103);
        //_activity.requestPermissions(new String[]{Manifest.permission.REQUEST_INSTALL_PACKAGES}, 103);
        }
}

2.5 权限已经申明(AndroidManifest.xml)了, 也向系统申请(代码)了,执行apk。

if (Build.VERSION.SDK_INT < 24) {
    //android 7.0及以下版本;
    Intent _intent = new Intent(Intent.ACTION_VIEW);
    _intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    _intent.setDataAndType(Uri.parse("file://" + _file), "application/vnd.android.package-archive");
    _activity.startActivity(_intent);
} else {
    //android 7.0及以上版本,需要apk安装权限;
    File _apkFile = new File(_file);
    if (_apkFile.isFile() && _apkFile.exists()) {
        // 这里必须和AndroidManifest.xml中定义的FileProvider中内容匹配。
        Uri _uri = FileProvider.getUriForFile(_activity, "com.trap.fileProvider", _apkFile);

        Intent _intent = new Intent(Intent.ACTION_VIEW);
        _intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        _intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        _intent.setDataAndType(_uri, "application/vnd.android.package-archive");

        //requestCode:1这个值是自定义的,随便填;
        //如果不重写Activity的onActivityResult方法,此值没意义。
        _activity.startActivityForResult(_intent, 1);

    }
}

到此,在线更新基本完成。

之前想法是自动判断手机是否有SD卡,有则下载到SD卡下的download文件夹,无则下载到当前应用的cache/download文件夹下。因为使用file://描述的uri不支持解读,只能使用FileProvider.getUriForFile生成的uri,这样子的话,我就不知道在paths.xml中如何配置了,只好放弃。在getExternalStorageDirectory()下创建了download保存下载文件,这个download是否与paths.xml中的name一项有关系,没有深入研究,弄了两天,真累,就算误打误撞成功了吧。

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 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、付费专栏及课程。

余额充值