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

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

    • 1、apk更新流程
    • 2、获取本地app内部版本工具类
    • 3、请求服务器获取版本数据及新旧版本比对
    • 4、下载最新版本apk
    • 5、监听下载是否完成并自动安装
    • 6、在AndroidManifest.xml开权限并配置receiver
    • 7、弹出框布局Dialog
    • 8、自定义Dialog
    • 9、使用xutils3升级最新版本数据库
    • 10、效果图
    • 11、总结

因为有的app应用不需要上线在应用市场,只需要在内部使用,所以就需要实现app内部检测最新版本功能,最近正好做了这个功能,所以把它分享出来:

1、apk更新流程

  1. 登录成功后请求服务器接口获取最新版本及更新内容(请求使用的xutils3框架)
  2. 获取本地app应用内版本versionCode与最新版本比较,若小于最新版本则弹框提示更新
  3. 更新下载apk并自动安装,进入主页面删除旧的apk包
  4. 程序启动初始化升级本地数据库

以上便是全部流程,步骤很简单,接下来就是代码实现

2、获取本地app内部版本工具类

package com.gtlxkj.cn.util;

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;
        }
    }

    /**
     * 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 "";
    }
 
}

3、请求服务器获取版本数据及新旧版本比对

 /**
 * 主页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;//是否检测版本初始化

    @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() {
    		@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"); 
			}
    	});
    }
}

后台用的springboot,具体接口比较简单就不展示了

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


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);
    }

此处使用DownloadManager 下载apk

5、监听下载是否完成并自动安装

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();
        }
 
    }
    
}

6、在AndroidManifest.xml开权限并配置receiver

权限:

  
  
  

receiver:

  
            
                
            
        

7、弹出框布局Dialog



 
    
 
        
 
        
 
       
 
        
		 
        
         
       
        
 
            

8、自定义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();
		}
    }
}


9、使用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 activityLists = new ArrayList();

    // 添加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();
        }
    }
}

10、效果图

Android实现app内部自动检测版本更新、自动安装及数据库更新升级_第1张图片

11、总结

数据库升级在此文中没有过多的说明,有需要的可以百度,有关资料还是很多的,也比较简单,打好的apk包放到服务器上,安卓请求这个apk链接就可以下载,版本升级切记打包的时候要使配置的版本和服务器接口内的版本一致同步,

你可能感兴趣的:(Android)