android 编写辅助服务器,简单实现Android APP自动更新

一般的安卓app都有自动更新功能,实现app的更新,以让用户体验新版本的功能,这里也是项目中用到的,今天就来总结一下,代码应该有点多,还请耐心点哈。安卓应用实现自动更新比较简单,这里跟大家介绍下:

第一步 服务器端:

服务端提供一个借口,或者网址,我这里就用的服务器是tomcat,这里提供一个网址如下://也就是一个json数据接口public static final String UPDATE_URL = "http://192.168.1.103:8080/update.json";

我们来看下json数据参数:{//app名字appname: "爱新闻1.1",//服务器版本号serverVersion: "2",//服务器标志serverFlag: "1",//是否强制更新lastForce: "1",//apk下载地址,这里我已经下载了官方的apk,放到了服务器里面updateurl: "http://192.168.1.103:8080/36Kr.apk",//版本的更新的描述upgradeinfo: "V1.1版本更新,你想不想要试一下哈!!!"}

好了以上的是服务器端的信息,在这里不需要多说了,我们来看下客户端的吧。

第二步 客户端需要实现

首先我们要去解析服务端给的json,那么我们就要来创建一个model类了(代码过多,这里只有字段,getter和setter方法自己创建)://app名字

private String appname;

//服务器版本

private String serverVersion;

//服务器标志

private String serverFlag;

//强制升级

private String lastForce;

//app最新版本地址

private String updateurl;

//升级信息

private String upgradeinfo;

在这里使用了一个辅助类,基本和model字段差不多:public class UpdateInformation {

public static String appname = MyApplication.getInstance()

.getResources().getString(R.string.app_name);

public static int localVersion = 1;// 本地版本

public static String versionName = ""; // 本地版本名

public static int serverVersion = 1;// 服务器版本

public static int serverFlag = 0;// 服务器标志

public static int lastForce = 0;// 之前强制升级版本

public static String updateurl = "";// 升级包获取地址

public static String upgradeinfo = "";// 升级信息

public static String downloadDir = "wuyinlei";// 下载目录

}

我们知道,我们在进入app的时候,这个时候如果检测到服务器端有了新的版本,就回弹出提示框,提示我们更新。这个我们在MainActivity里面处理逻辑(onCreate()方法里面):OkhttpManager.getAsync(Config.UPDATE_URL, new OkhttpManager.DataCallBack() {

@Override

public void requestFailure(Request request, Exception e) {

}

@Override

public void requestSuccess(String result) {

try {

Log.d("wuyiunlei",result);

JSONObject object = new JSONObject(result);

UpdateInfoModel model = new UpdateInfoModel();

model.setAppname(object.getString("appname"));

model.setLastForce(object.getString("lastForce"));

model.setServerFlag(object.getString("serverFlag"));

model.setServerVersion(object.getString("serverVersion"));

model.setUpdateurl(object.getString("updateurl"));

model.setUpgradeinfo(object.getString("upgradeinfo"));

tmpMap.put(DeliverConsts.KEY_APP_UPDATE, model);

} catch (JSONException e) {

e.printStackTrace();

}

//发送广播

sendBroadcast(new Intent(UpdateReceiver.UPDATE_ACTION));

}

});

当然了,我们也要注册和结束广播:private void registerBroadcast() {

mUpdateReceiver = new UpdateReceiver(false);

mIntentFilter = new IntentFilter(UpdateReceiver.UPDATE_ACTION);

this.registerReceiver(mUpdateReceiver, mIntentFilter);

}

private void unRegisterBroadcast() {

try {

this.unregisterReceiver(mUpdateReceiver);

} catch (Exception e) {

e.printStackTrace();

}

}

好了,接下来我们看下我们自定义的广播接收者UpdateReceiver .java:public class UpdateReceiver extends BroadcastReceiver {

private AlertDialog.Builder mDialog;

public static final String UPDATE_ACTION = "wuyinlei_aixinwen";

private SharedPreferencesHelper mSharedPreferencesHelper;

private boolean isShowDialog;

public UpdateReceiver() {

}

public UpdateReceiver(boolean isShowDialog) {

super();

this.isShowDialog = isShowDialog;

}

@Override

public void onReceive(Context context, Intent intent) {

mSharedPreferencesHelper = mSharedPreferencesHelper

.getInstance(MyApplication.getInstance());

//当然了,这里也可以直接new处hashmap

HashMap tempMap = MyApplication.getInstance()

.getTempMap();

UpdateInfoModel model = (UpdateInfoModel) tempMap

//就是一个标志

.get(DeliverConsts.KEY_APP_UPDATE);

try {

UpdateInformation.localVersion = MyApplication

.getInstance()

//包管理独享

.getPackageManager()

//包信息

.getPackageInfo(

MyApplication.getInstance()

.getPackageName(), 0).versionCode;

/**

* 获取到当前的版本名字

*/

UpdateInformation.versionName = MyApplication

.getInstance()

.getPackageManager()

.getPackageInfo(

MyApplication.getInstance()

.getPackageName(), 0).versionName;

} catch (Exception e) {

e.printStackTrace();

}

//app名字

UpdateInformation.appname = MyApplication.getInstance()

.getResources().getString(R.string.app_name);

//服务器版本

UpdateInformation.serverVersion = Integer.parseInt(model

.getServerVersion());

//服务器标志

UpdateInformation.serverFlag = Integer.parseInt(model.getServerFlag());

//强制升级

UpdateInformation.lastForce = Integer.parseInt(model.getLastForce());

//升级地址

UpdateInformation.updateurl = model.getUpdateurl();

//升级信息

UpdateInformation.upgradeinfo = model.getUpgradeinfo();

//检查版本

checkVersion(context);

}

/**

* 检查版本更新

*/

public void checkVersion(Context context) {

if (UpdateInformation.localVersion 

// 需要进行更新

mSharedPreferencesHelper.putIntValue(

//有新版本

SharedPreferencesTag.IS_HAVE_NEW_VERSION, 1);

//更新

update(context);

} else {

mSharedPreferencesHelper.putIntValue(

SharedPreferencesTag.IS_HAVE_NEW_VERSION, 0);

if (isShowDialog) {

//没有最新版本,不用升级

noNewVersion(context);

}

clearUpateFile(context);

}

}

/**

* 进行升级

*/

private void update(Context context) {

if (UpdateInformation.serverFlag == 1) {

// 官方推荐升级

if (UpdateInformation.localVersion 

//强制升级

forceUpdate(context);

} else {

//正常升级

normalUpdate(context);

}

} else if (UpdateInformation.serverFlag == 2) {

// 官方强制升级

forceUpdate(context);

}

}

/**

* 没有新版本

*/

private void noNewVersion(final Context context) {

mDialog = new AlertDialog.Builder(context);

mDialog.setTitle("版本更新");

mDialog.setMessage("当前为最新版本");

mDialog.setNegativeButton("确定", new DialogInterface.OnClickListener() {

@Override

public void onClick(DialogInterface dialog, int which) {

dialog.dismiss();

}

}).create().show();

}

/**

* 强制升级 ,如果不点击确定升级,直接退出应用

*/

private void forceUpdate(final Context context) {

mDialog = new AlertDialog.Builder(context);

mDialog.setTitle("版本更新");

mDialog.setMessage(UpdateInformation.upgradeinfo);

mDialog.setPositiveButton("确定", new DialogInterface.OnClickListener() {

@Override

public void onClick(DialogInterface dialog, int which) {

Intent mIntent = new Intent(context, UpdateService.class);

mIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

mIntent.putExtra("appname", UpdateInformation.appname);

mIntent.putExtra("appurl", UpdateInformation.updateurl);

//启动服务

context.startService(mIntent);

}

}).setNegativeButton("退出", new DialogInterface.OnClickListener() {

@Override

public void onClick(DialogInterface dialog, int which) {

// 直接退出应用

//ManagerActivity.getInstance().finishActivity();

System.exit(0);

}

}).setCancelable(false).create().show();

}

/**

* 正常升级,用户可以选择是否取消升级

*/

private void normalUpdate(final Context context) {

//这里是显示dialog,确定点击升级 ,取消不升级

}

/**

* 清理升级文件

*/

private void clearUpateFile(final Context context) {

File updateDir;

File updateFile;

if (Environment.MEDIA_MOUNTED.equals(Environment

.getExternalStorageState())) {

updateDir = new File(Environment.getExternalStorageDirectory(),

UpdateInformation.downloadDir);

} else {

updateDir = context.getFilesDir();

}

updateFile = new File(updateDir.getPath(), context.getResources()

.getString(R.string.app_name) + ".apk");

if (updateFile.exists()) {

Log.d("update", "升级包存在,删除升级包");

updateFile.delete();

} else {

Log.d("update", "升级包不存在,不用删除升级包");

}

}

}

最后我们来看下服务吧UpdateService .java:/**

* 不要忘记注册,在mainfest文件中

*/

public class UpdateService extends Service {

// BT字节参考量

private static final float SIZE_BT = 1024L;

// KB字节参考量

private static final float SIZE_KB = SIZE_BT * 1024.0f;

// MB字节参考量

private static final float SIZE_MB = SIZE_KB * 1024.0f;

private final static int DOWNLOAD_COMPLETE = 1;// 完成

private final static int DOWNLOAD_NOMEMORY = -1;// 内存异常

private final static int DOWNLOAD_FAIL = -2;// 失败

private String appName = null;// 应用名字

private String appUrl = null;// 应用升级地址

private File updateDir = null;// 文件目录

private File updateFile = null;// 升级文件

// 通知栏

private NotificationManager updateNotificationManager = null;

private Notification updateNotification = null;

private Intent updateIntent = null;// 下载完成

private PendingIntent updatePendingIntent = null;// 在下载的时候

@Override

public IBinder onBind(Intent arg0) {

return null;

}

@Override

public void onStart(Intent intent, int startId) {

super.onStart(intent, startId);

appName = intent.getStringExtra("appname");

appUrl = intent.getStringExtra("appurl");

updateNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);

updateNotification = new Notification();

//通知图标

updateNotification.icon = R.mipmap.head;

//通知信息描述

updateNotification.tickerText = "正在下载 " + appName;

updateNotification.when = System.currentTimeMillis();

updateIntent = new Intent(this, MyApplication.class);

updatePendingIntent = PendingIntent.getActivity(this, 0, updateIntent,

0);

updateNotification.contentIntent = updatePendingIntent;

updateNotification.contentIntent.cancel();

updateNotification.contentView = new RemoteViews(getPackageName(),

//这个布局很简单,就是一个图片和两个textview,分别是正在下载和下载进度

R.layout.download_notification);

updateNotification.contentView.setTextViewText(

R.id.download_notice_name_tv, appName + " 正在下载");

updateNotification.contentView.setTextViewText(

R.id.download_notice_speed_tv, "0MB (0%)");

updateNotificationManager.notify(0, updateNotification);

new UpdateThread().execute();

}

/**

* 在这里使用了asynctask异步任务来下载

*/

class UpdateThread extends AsyncTask {

@Override

protected Integer doInBackground(Void... params) {

return downloadUpdateFile(appUrl);

}

@Override

protected void onPostExecute(Integer result) {

super.onPostExecute(result);

if (result == DOWNLOAD_COMPLETE) {

Log.d("update", "下载成功");

String cmd = "chmod 777 " + updateFile.getPath();

try {

Runtime.getRuntime().exec(cmd);

} catch (IOException e) {

e.printStackTrace();

}

Uri uri = Uri.fromFile(updateFile);

//安装程序

Intent installIntent = new Intent(Intent.ACTION_VIEW);

installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

installIntent.setDataAndType(uri,

"application/vnd.android.package-archive");

updatePendingIntent = PendingIntent.getActivity(

UpdateService.this, 0, installIntent, 0);

updateNotification.contentIntent = updatePendingIntent;

updateNotification.contentView.setTextViewText(

R.id.download_notice_speed_tv,

getString(R.string.update_notice_finish));

updateNotification.tickerText = appName + "下载完成";

updateNotification.when = System.currentTimeMillis();

updateNotification.defaults = Notification.DEFAULT_SOUND;

updateNotification.flags |= Notification.FLAG_AUTO_CANCEL;

updateNotificationManager.notify(0, updateNotification);

//启动安装程序

UpdateService.this.startActivity(installIntent);

stopSelf();

} else if (result == DOWNLOAD_NOMEMORY) {

//如果内存有问题

updateNotification.tickerText = appName + "下载失败";

updateNotification.when = System.currentTimeMillis();

updateNotification.contentView.setTextViewText(

R.id.download_notice_speed_tv,

getString(R.string.update_notice_nomemory));

updateNotification.flags |= Notification.FLAG_AUTO_CANCEL;

updateNotification.defaults = Notification.DEFAULT_SOUND;

updateNotificationManager.notify(0, updateNotification);

stopSelf();

} else if (result == DOWNLOAD_FAIL) {

//下载失败

updateNotification.tickerText = appName + "下载失败";

updateNotification.when = System.currentTimeMillis();

updateNotification.contentView.setTextViewText(

R.id.download_notice_speed_tv,

getString(R.string.update_notice_error));

updateNotification.flags |= Notification.FLAG_AUTO_CANCEL;

updateNotification.defaults = Notification.DEFAULT_SOUND;

updateNotificationManager.notify(0, updateNotification);

stopSelf();

}

}

}

/**

* 下载更新程序文件

* @param downloadUrl   下载地址

* @return

*/

private int downloadUpdateFile(String downloadUrl) {

int count = 0;

long totalSize = 0;   //总大小

long downloadSize = 0;   //下载的大小

retrun OktttpUtil.down(url)// 省略

}

/**

* 可用内存大小

*/

private boolean MemoryAvailable(long fileSize) {

fileSize += (1024 << 10);

if (MemoryStatus.externalMemoryAvailable()) {

if ((MemoryStatus.getAvailableExternalMemorySize() <= fileSize)) {

if ((MemoryStatus.getAvailableInternalMemorySize() > fileSize)) {

createFile(false);

return true;

} else {

return false;

}

} else {

createFile(true);

return true;

}

} else {

if (MemoryStatus.getAvailableInternalMemorySize() <= fileSize) {

return false;

} else {

createFile(false);

return true;

}

}

}

/**

* 获取下载进度

*/

public static String getMsgSpeed(long downSize, long allSize) {

StringBuffer sBuf = new StringBuffer();

sBuf.append(getSize(downSize));

sBuf.append("/");

sBuf.append(getSize(allSize));

sBuf.append(" ");

sBuf.append(getPercentSize(downSize, allSize));

return sBuf.toString();

}

/**

* 获取到当前的下载百分比

*/

public static String getPercentSize(long downSize, long allSize) {

String percent = (allSize == 0 ? "0.0" : new DecimalFormat("0.0")

.format((double) downSize / (double) allSize * 100));

return "(" + percent + "%)";

}

/**

* 创建file文件

*/

private void createFile(boolean sd_available) {

if (sd_available) {

updateDir = new File(Environment.getExternalStorageDirectory(),

UpdateInformation.downloadDir);

} else {

updateDir = getFilesDir();

}

updateFile = new File(updateDir.getPath(), appName + ".apk");

if (!updateDir.exists()) {

updateDir.mkdirs();

}

if (!updateFile.exists()) {

try {

updateFile.createNewFile();

} catch (IOException e) {

e.printStackTrace();

}

} else {

updateFile.delete();

try {

updateFile.createNewFile();

} catch (IOException e) {

e.printStackTrace();

}

}

}

}

这个时候,可能看到服务怎么这么多代码啊,我头都大了,不要着急,我们一步一步说明一下,这里逻辑很简单,就是在通知栏中,用到了通知,这个时候我们有三种情况,造成了我们好多代码的重复,(你也可以不必考虑那么多情况),还有,里面有了几个工具类,没有提取出来,分别是获取sdcard大小是否可用(创建文件夹),获取当前下载进度,获取应用大小,下载文件,这里也可以使用第三方框架来下载。里面的重要的地方都有注释,如果有疑问,可用互相讨论一下。

这里我们就简单的上几张图看看吧:提示更新图:

1404aa10ff1b0780fa98888af9e81445.png

更新下载通知:

8a2e7f5e8968232e8653b7a71d17a13a.png

下载完成后安装图:

2a5203cffb9936b7718fbc03e19ab904.png

最新版应用主界面图(这里我下载的是36kr官方的app,我在应用中心下载好的,嘿嘿):

47740de901c65a5aa7a875a1cb015de4.png

当然了哈,这里我写的还是有点问题的,每次进入都会提示,如果有必要,也可以实现是否要自动更新,用服务,也就是点击是否自动更新,如果不是自动更新,就不会去触发服务端接口信息,如果是自动更新,就去触发,来获取最新的app版本。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值