Android实现app内部自动检测版本更新、自动安装及数据库更新升级

Android实现app内部自动检测版本更新、自动安装及数据库更新升级
一、apk更新流程
二、获取本地app内部版本工具类
三、请求服务器获取版本数据及新旧版本比对
四、下载最新版本apk
五、监听下载是否完成并自动安装
六、在AndroidManifest.xml开权限并配置receiver
七、弹出框布局Dialog
八、自定义Dialog
九、使用xutils3升级最新版本数据库
十、效果图
十一、总结java

由于有的app应用不须要上线在应用市场,只须要在内部使用,因此就须要实现app内部检测最新版本功能,最近正好作了这个功能,因此把它分享出来:
一、apk更新流程
登陆成功后请求服务器接口获取最新版本及更新内容(请求使用的xutils3框架)
获取本地app应用内版本versionCode与最新版本比较,若小于最新版本则弹框提示更新
更新下载apk并自动安装,进入主页面删除旧的apk包
程序启动初始化升级本地数据库
以上即是所有流程,步骤很简单,接下来就是代码实现android

二、获取本地app内部版本工具类
package com.gtlxkj.cn.util;spring

import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Environment;数据库

public class VersionUtils {
    /**
     * 检查是否存在SDCard
     *
     * @return
     */
    public static boolean hasSdcard() {
        String state = Environment.getExternalStorageState();
        if (state.equals(Environment.MEDIA_MOUNTED)) {
            return true;
        } else {
            return false;
        }
    }springboot

    /**
     * 2 * 获取版本
     */
    public static int getVersion(Context context) {
        try {
            PackageManager manager = context.getPackageManager();
            PackageInfo info = manager.getPackageInfo(context.getPackageName(),0);
            int versioncode = info.versionCode;
            return versioncode;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }
    
    /**
     * 2 * 获取版本名称
     */
    public static String getVersionName(Context context) {
        try {
            PackageManager manager = context.getPackageManager();
            PackageInfo info = manager.getPackageInfo(context.getPackageName(),0);
            String version = info.versionName;
            return version;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }
 
}服务器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
三、请求服务器获取版本数据及新旧版本比对
 /**
 * 主页Activity
 * 
 */
@ContentView(R.layout.activity_home)
public class HomeActivity extends BaseActivity implements View.OnClickListener {网络

    @ViewInject(R.id.btn_upload)
    private Button btn_upload;
    @ViewInject(R.id.update_apk)
    private TextView update_apk;
    private Context context = HomeActivity.this;
    private VersionDialog dialog;
    private boolean flag;//是否检测版本初始化app

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.i("HomeActivity", "onCreate"); 
      
       initListener();
       
       Utils.deleteLocal(new File(ConfigurationUtil.APK_PATH_ABSOULT+"GTLXKJ.apk"));//删除旧的apk
       flag=true;
       // 获取本版本号,是否更新
       getVersion(VersionUtils.getVersion(this));
    }框架

    //初始点击事件
    private void initListener(){
        Log.i("HomeActivity", "initListener"); 
        update_apk.setOnClickListener(this);
        update_apk.setText("版本号 V"+Tools.getVersionName(this));
    }
    
    /**
     * 点击事件
     * @param view
     */
    public void onClick(View v) {
        Log.i("HomeActivity", "onClick"); 
        switch(v.getId()){
            case R.id.update_apk:
                flag=false;
                getVersion(Tools.getVersion(this));
                break;    
        }
    }
    
   
    
  //版本更新弹出框
  public  void showUploadApkDialog(String content,String versionName) {
        Log.i("HomeActivity", "showUploadTaskDialog"); 
        dialog = new VersionDialog(this,R.style.mystyle,this,R.layout.version__update_dialog,content,versionName);
        dialog.show();
   }
    
    
    
    // 获取更新版本号
    private void getVersion(final int vision) {
        if (!NetWorkUtil.isNetworkAvalible(context)) {
            Toast.makeText(HomeActivity.this,"请检查网络",Toast.LENGTH_SHORT).show();
            return;
        }
        
         RequestParams params = new RequestParams(ConfigurationUtil.WEBVERSION);
         x.http().get(params, new Callback.ProgressCallback<String>() {
            @Override
            public void onSuccess(String result) {
                Log.i("onSuccess", "onSuccess"); 
                try{
                       JSONObject object = new JSONObject(result);
                       //返回状态
                       String status = object.optString("code");
                       //返回的更新内容
                      String content = object.optString("content");
                      //返回的版本号
                      String versionName = object.optString("msg");
                      //返回版本
                       String nversion = object.optString("data");
                       if("1".equals(status)){
                           int newversion = Integer.parseInt(nversion);
                           if (newversion != vision) {//新旧版本比较
                               if (vision < newversion) {//旧版本低于新版本则更新
                                   System.out.println("新版本:v"+newversion + "   旧版本v"+ vision);
                                   // 版本号不一样
                                   showUploadApkDialog(content,versionName);
                               }
                           }else if(!flag){
                               Toast.makeText(HomeActivity.this,"已是最新版本",Toast.LENGTH_SHORT).show();
                          }
                       }
                }catch(Exception e){
                    e.printStackTrace();
                    Log.e("onSuccess", "Error"); 
                }
            }
            @Override
            public void onCancelled(CancelledException arg0) {
                Log.i("onCancelled", "onCancelled"); 
            }
            @Override
            public void onError(Throwable arg0, boolean arg1) {
                Log.e("onError", "onError"); 
                 Toast.makeText(HomeActivity.this,"请求服务器无响应",Toast.LENGTH_SHORT).show();
            }
            @Override
            public void onFinished() {
                Log.i("onFinished", "onFinished"); 
            }
            @Override
            public void onLoading(long arg0, long arg1, boolean arg2) {
                Log.i("onLoading", "onLoading"); 
            }
            @Override
            public void onStarted() {
                Log.i("onStarted", "onStarted"); 
            }
            @Override
            public void onWaiting() {
                Log.i("onWaiting", "onWaiting"); 
            }
        });
    }
}ide

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
后台用的springboot,具体接口比较简单就不展现了

AndroidManifest.xml文件中这里配置版本号,发布新版本apk到服务器上时不要忘了修改这里的版本号

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.gtlxkj.cn"
    android:versionCode="5"
    android:versionName="5.0.0" >
1
2
3
4
四、下载最新版本apk
    //下载apk
    public void downloadApk(String apkUrl) throws PackageManager.NameNotFoundException {
        Utils.deleteLocal(new File(ConfigurationUtil.APK_PATH_ABSOULT+"GTLXKJ.apk"));//删除旧的apk
        Uri uri = Uri.parse(apkUrl);
        DownloadManager downloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
        DownloadManager.Request request = new DownloadManager.Request(uri);
        // 设置容许使用的网络类型,这里是移动网络和wifi均可以
        request.setAllowedNetworkTypes(request.NETWORK_MOBILE | request.NETWORK_WIFI);
        //设置是否容许漫游
        request.setAllowedOverRoaming(true);
        //设置文件类型
        MimeTypeMap mimeTypeMap = MimeTypeMap.getSingleton();
        String mimeString = mimeTypeMap.getMimeTypeFromExtension(MimeTypeMap.getFileExtensionFromUrl(apkUrl));
        request.setMimeType(mimeString);
        //在通知栏中显示
        request.setNotificationVisibility(request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
        request.setTitle("正在下载");
        request.setVisibleInDownloadsUi(true);
        //sdcard目录下的download文件夹
        request.setDestinationInExternalPublicDir(ConfigurationUtil.APK_PATH, "GTLXKJ.apk");
        // 将下载请求放入队列
        downloadManager.enqueue(request);
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
此处使用DownloadManager 下载apk

五、监听下载是否完成并自动安装
package com.gtlxkj.cn.activity;

import java.io.File;

import com.gtlxkj.cn.util.ConfigurationUtil;
import com.gtlxkj.cn.util.Utils;

import android.app.DownloadManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;

public class InstallReceiver extends BroadcastReceiver {
     
    // 安装下载接收器
    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals(DownloadManager.ACTION_DOWNLOAD_COMPLETE)) {
            installApk(context);
        }
  }
 
    // 安装Apk
    private void installApk(Context context) {
        try {
            Intent i = new Intent(Intent.ACTION_VIEW);
            String filePath = ConfigurationUtil.APK_PATH_ABSOULT+"GTLXKJ.apk";
            System.out.println(filePath);
            i.setDataAndType(Uri.parse("file://" + filePath), "application/vnd.android.package-archive");
            i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(i);
        } catch (Exception e) {
            e.printStackTrace();
        }
 
    }
    
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
六、在AndroidManifest.xml开权限并配置receiver
权限:

  <uses-permission android:name="android.permission.INTERNET" />
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

1
2
3
4
receiver:

  <receiver
            android:name="com.gtlxkj.cn.activity.InstallReceiver">
            <intent-filter>
                <action android:name="android.intent.action.DOWNLOAD_COMPLETE" />
            </intent-filter>
        </receiver>
1
2
3
4
5
6
七、弹出框布局Dialog
<?xml version="1.0" encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="300dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:background="@drawable/dialog4" >
 
    <LinearLayout
        android:id="@+id/lay_finish"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:orientation="vertical"
        android:scrollbars="vertical" >
 
        <TextView
            android:id="@+id/lay_view"
            android:layout_width="fill_parent"
            android:layout_height="50dp"
            android:gravity="center"
            android:text="版本更新"
            android:textColor="#5b5d61"
            android:textSize="18sp" />
 
        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="1dip"
            android:background="#D1D1D1" />
 
       <ScrollView
        android:id="@+id/lay_work"
        android:layout_width="match_parent"
        android:layout_height="250dp"
        android:layout_marginTop="10dp"
        android:layout_marginBottom="10dp"
        android:orientation="vertical"
        android:scrollbars="none">
 
        <TextView
            android:id="@+id/version_content"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="8dp"
            android:layout_marginRight="8dp"
            android:textColor="#5b5d61"
            android:textSize="16sp" />
         </ScrollView>
        
         <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="1dip"
            android:background="#D1D1D1" />
       
        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="40dp"
            android:orientation="horizontal" >
 
            <Button
                android:id="@+id/cancal"
                android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                android:layout_weight="1"
                android:background="@null"
                android:text="稍后"
                android:textColor="#91c11e"
                android:textSize="15dp" />
 
            <LinearLayout
                android:layout_width="1dp"
                android:layout_height="fill_parent"
                android:background="#D1D1D1" />
 
            <Button
                android:id="@+id/update"
                android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                android:layout_weight="1"
                android:background="@null"
                android:text="更新"
                android:textColor="#91c11e"
                android:textSize="15dp" />
        </LinearLayout>
    </LinearLayout>
 
</LinearLayout>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
八、自定义Dialog
package com.gtlxkj.cn.dialog;

import com.gtlxkj.cn.R;
import com.gtlxkj.cn.activity.HomeActivity;
import com.gtlxkj.cn.util.ConfigurationUtil;

import android.app.Dialog;
import android.content.Context;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

/**
 * 自定义dialog
 */
public class VersionDialog extends Dialog implements
        View.OnClickListener {

    /**
     * 布局文件
     **/
    int layoutRes;

    /**
     * 上下文对象
     **/
    Context context;
    

    /**
     * 取消按钮
     **/
    private Button bt_cancal;

    /**
     * 更新按钮
     **/
    private Button bt_delect;
    
    private String content;//版本内容
    
    private String versionName;//版本号
    
    private HomeActivity homeActivity;
    
    
    public VersionDialog(Context context) {
        super(context);
        this.context = context;
    }

    /**
     * 自定义布局的构造方法
     *
     * @param context
     * @param resLayout
     */
    public VersionDialog(Context context, int resLayout) {
        super(context);
        this.context = context;
        this.layoutRes = resLayout;
    }

    /**
     * 自定义主题及布局的构造方法
     *
     * @param context
     * @param theme
     * @param resLayout
     * @param postion
     */
    public VersionDialog(Context context,int theme, HomeActivity activity,int resLayout,String content,String versionName) {
        super(context, theme);
        this.context = context;
        this.content = content;
        this.layoutRes = resLayout;
        this.homeActivity = activity;
        this.versionName = versionName;
    }

    

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // 指定布局
        this.setContentView(layoutRes);
        TextView  textView=(TextView) findViewById(R.id.version_content);
        TextView  titleView=(TextView) findViewById(R.id.lay_view);
        textView.setText("更新内容:\n\n"+content);
        titleView.setText("发现新版本 "+versionName);
        // 根据id在布局中找到控件对象
        bt_cancal = (Button) findViewById(R.id.cancal);
        bt_delect = (Button) findViewById(R.id.update);
        // 为按钮绑定点击事件监听器
        bt_cancal.setOnClickListener(this);
        bt_delect.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {

            case R.id.update:
                optUpdateApk();
                this.dismiss();
                break;

            // 取消按钮
            case R.id.cancal:
                this.dismiss();

            default:
                break;
        }
    }
    /**
     * 操做  版本更新
     *
     */
    private void optUpdateApk( ) {
        try {
            homeActivity.downloadApk(ConfigurationUtil.APKHOST);
        } catch (NameNotFoundException e) {
            e.printStackTrace();
        }
    }
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
九、使用xutils3升级最新版本数据库
注意此升级代码是在onUpgrade方法内实现,
这样更新完app后从新启动就会初始化升级本地数据库结构了

public class LXApplication extends Application {
    
    // Effective Java 初版推荐写法
    private static class LXApplicationHolder {
        private static final LXApplication INSTANCE = new LXApplication();
    }
    
    public LXApplication() {
    }

    public static final LXApplication getInstance() {
        return LXApplicationHolder.INSTANCE;
    }

    public static DbManager.DaoConfig daoConfig;

    @Override
    public void onCreate() {
        super.onCreate();
        CrashHandler crashHandler = CrashHandler.getInstance();
        crashHandler.init(this);
        x.Ext.init(this);
        x.Ext.setDebug(true);
        dbinit();
    }
    //xutils3初始化
    private void dbinit() {
        File file = new File(ConfigurationUtil.SDFILE + "db");
        if (!file.exists()) {
            file.mkdirs();
        }
        daoConfig = new DbManager.DaoConfig()
                .setDbName(ConfigurationUtil.DBNAME)
                .setDbDir(file).setDbVersion(ConfigurationUtil.DBVERSION)
                .setAllowTransaction(true)
                .setDbOpenListener(new DbManager.DbOpenListener() {
            @Override
            public void onDbOpened(DbManager db) {
                // 开启WAL, 对写入加速提高巨大
                db.getDatabase().enableWriteAheadLogging();
            }
        }).setDbUpgradeListener(new DbManager.DbUpgradeListener() {
            @Override
            public void onUpgrade(DbManager db, int oldVersion, int newVersion) {//数据库升级
                try {
                     for (int j = oldVersion; j <= newVersion; j++) {
                        switch(newVersion){
                            case 2:
                                //增长表字段
                                db.addColumn(Person.class, "name");
                               break;
                             case 3:
                               /**
                                *保留历史数据的升级数据库
                                */

                               // db.execSQL(""); //第一步将旧表改成临时表
        
                               //db.execSQL(""); //第二步建立新表(新添加的字段或去掉 的字段)
        
                               //db.execSQL(""); //第三步将旧表中的原始数据保存到新表中以防遗失
        
                               //db.execSQL(""); //第四步删除临时备份表
                               break;
                            case 4://其余操做
                                // TODO: ...
                                // db.dropTable(...);
                                // ...
                                // or
                                // db.dropDb();
                                break;
                            default:
                                break;
                         }
                     }
                } catch (DbException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                
            }
        }).setTableCreateListener(new DbManager.TableCreateListener() {// 设置表建立的监听

            @Override
            public void onTableCreated(DbManager arg0, TableEntity<?> arg1) {
                Log.i("sjl__", "onTableCreated:" + arg1.getName());
            }
        });
    }

    
    public DbManager.DaoConfig getDbConfig() {
        if (daoConfig == null) {
            dbinit();
        }
        return daoConfig;
    }

    private static List<Activity> activityLists = new ArrayList<Activity>();

    // 添加Activity到容器中
    public static void addActivity(Activity activity) {
        activityLists.add(activity);
    }

    // 遍历全部Activity并finish
    public static void exit() {
        try {
            for (Activity activity : activityLists) {
                activity.finish();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
十、效果图

十一、总结 数据库升级在此文中没有过多的说明,有须要的能够百度,有关资料仍是不少的,也比较简单,打好的apk包放到服务器上,安卓请求这个apk连接就能够下载,版本升级切记打包的时候要使配置的版本和服务器接口内的版本一致同步, ———————————————— 版权声明:本文为CSDN博主「Nirvana_lss」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处连接及本声明。 原文连接:https://blog.csdn.net/Nirvana_lss/article/details/89879571

相关文章
相关标签/搜索