您的位置:首页 > 移动开发 > Android开发

android 实现版本更新和下载安装

2015-05-17 19:36 507 查看
在开发android APP时候 经常用到的一个技术 就是检查目前手机端APP的版本,如果手机端版本较低 ,就会实现下载新版本和安装。

实现的过程的大体思路是这样的:

首先得到本地的版本,其次向服务器发送请求,参数为当前的版本号,服务器会比较服务端的版本号,返回客户端一个对象,对象中包含是否需要更新(),比较两个版本,如果不一致,则客户端从服务器下载新的版本并且安装,这里下载和安装使用了第三方插件afinal_0.5.1_bin.jar 该插件能够实现下载和安装。

由于我是刚进入android的开发,并且第一次写博文,不足之处,请大家原谅和多多指点。

首先第一步不必多说,导入afinal_0.5.1_bin.jar包

第二步,因为为了提高效果,会使用Notification提示栏,这里先准备好他的布局。notification_layout_big.xml 代码如下

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="match_parent"

android:layout_height="wrap_content"

>

<ImageView

android:id="@+id/imageView1"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_alignParentLeft="true"

android:layout_centerVertical="true"

android:src="@drawable/ic_launcher" />

<RelativeLayout

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_centerVertical="true"

android:layout_toRightOf="@+id/imageView1"

android:layout_marginTop="20dp"

android:layout_marginLeft="20dp"

>

<TextView

android:id="@+id/tv_versionUpdate"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="涂吧版本更新,点击下载"

android:textColor="@color/white"

android:textSize="18sp" />

<TextView

android:id="@+id/tv_versionAbstract"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_below="@+id/tv_versionUpdate"

android:text="2222"

android:textSize="16sp" />

</RelativeLayout>

</RelativeLayout>

然后就是其他类的代码了,首先是Update类,功能是获得当前版本

package com.example.update;

import java.util.ArrayList;

import java.util.List;

import org.apache.http.NameValuePair;

import org.apache.http.message.BasicNameValuePair;

import org.json.JSONException;

import org.json.JSONObject;

import android.app.Activity;

import android.content.Context;

import android.content.Intent;

import android.content.pm.PackageInfo;

import android.content.pm.PackageManager;

import android.content.pm.PackageManager.NameNotFoundException;

import android.widget.Toast;

import com.example.update.UpdateAsyncTask.UpdateListener;

public class Update {

/*

* 服务器需求,定义两个借口

* 接口一:

* 本地上传当前版本号以后,返回是否需要更新

* 如果需要更新,则返回更新的地址,及新版本的描述

* 接口参数

* oldVersion

* 返回结果

* address

* abstract

*

* 接口二:新版本apk的下载地址

* loadUrl

*

*/

/**

* 检测当前版本和服务器版本是否相同

*/

String versionUrl; //检查版本名的url,即接口一

String curVersion; //当前版本名

private void checkVersion(final Context context){

int versioncode ;

try {

PackageManager manager = context.getPackageManager();

PackageInfo info = manager.getPackageInfo(context.getPackageName(), 0);

curVersion = info.versionName;

versioncode = info.versionCode;

UpdateNotificationReceiver.VersionName = curVersion;

} catch (NameNotFoundException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

List<NameValuePair> params = new ArrayList<NameValuePair>();

params.add(new BasicNameValuePair("oldVersion",curVersion));

UpdateAsyncTask task = new UpdateAsyncTask(context, versionUrl, new UpdateListener() {

@Override

public VersionBean parseData(String data) {

//自定义解析

VersionBean bean = new VersionBean();

try {

JSONObject updateObj = new JSONObject(data);

bean.setVersion_address(updateObj.getString("address"));

bean.setVersion_abstract(updateObj.getString("abstract"));

} catch (JSONException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

return bean;

}

@Override

public void onLoadDataSuccess(VersionBean object) {

//重新存储

VersionBean bean = (VersionBean) object;

//这里是需要更新时候需要需要发送广播在广播中启动服务

Intent intent = new Intent(context,UpdateNotificationReceiver.class);

intent.putExtra("address", bean.getVersion_address());

intent.putExtra("abstract", bean.getVersion_abstract());

context.sendBroadcast(intent);

}

@Override

public void onLoadDataFailed(String tag) {

Toast.makeText(context, "当前已是最新版本", Toast.LENGTH_SHORT).show();

}

}, params);

task.execute(VersionBean.class);

}

}

这个类使用时需要将checkVersion()方法改为公有,这样方便在事件处理中调用,这里大家根据需要改吧,下面就是UpdateAsyncTask 类:

package com.example.update;

import java.io.UnsupportedEncodingException;

import java.util.List;

import org.apache.http.HttpResponse;

import org.apache.http.NameValuePair;

import org.apache.http.client.entity.UrlEncodedFormEntity;

import org.apache.http.client.methods.HttpPost;

import org.apache.http.impl.client.DefaultHttpClient;

import org.apache.http.params.BasicHttpParams;

import org.apache.http.params.HttpConnectionParams;

import org.apache.http.protocol.HTTP;

import org.apache.http.util.EntityUtils;

import org.json.JSONObject;

import android.content.Context;

import android.os.AsyncTask;

import android.text.TextUtils;

public class UpdateAsyncTask extends AsyncTask<Class, Integer, VersionBean>{

private Context mContext;

private String mUrl;

private UpdateListener mListener;

private List<NameValuePair> mList;

public UpdateAsyncTask(Context context,String url,UpdateListener listener,List<NameValuePair> list){

this.mContext = context;

this.mUrl = url;

this.mListener = listener;

this.mList = list;

}

@Override

protected void onPreExecute() {

// TODO Auto-generated method stub

super.onPreExecute();

}

@Override

protected VersionBean doInBackground(Class... arg0) {

try {

BasicHttpParams bhp = new BasicHttpParams();

HttpConnectionParams.setConnectionTimeout(bhp, 4*1000);

HttpConnectionParams.setSoTimeout(bhp, 4*1000);

DefaultHttpClient dhClient = new DefaultHttpClient(bhp);

HttpPost post = new HttpPost(this.mUrl);

post.setEntity(new UrlEncodedFormEntity(mList,HTTP.UTF_8));

HttpResponse response = dhClient.execute(post);

//result格式,Json数据,包含 state 和 data两项

String result = EntityUtils.toString(response.getEntity());

JSONObject jsonObj = new JSONObject(result);

String state = jsonObj.getString("state");

String data = jsonObj.getString("data");

//表示没有更新

if("0".equals(state)){

return null;

}

//有要更新的包

else{

if(TextUtils.isEmpty(data)){

return null;

}else{

VersionBean bean = mListener.parseData(data);

return bean;

}

}

} catch (Exception e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

return null;

}

@Override

protected void onPostExecute(VersionBean bean) {

// TODO Auto-generated method stub

super.onPostExecute(bean);

if(bean == null){

mListener.onLoadDataFailed("没有要更新的包");

}else{

mListener.onLoadDataSuccess(bean);

}

}

public interface UpdateListener{

public void onLoadDataSuccess(VersionBean object);

public void onLoadDataFailed(String tag);

public VersionBean parseData(String data);

}

}

接下来是接收广播类,在该类会启动服务并且创建提示栏

package com.example.update;

import android.app.Notification;

import android.app.NotificationManager;

import android.app.PendingIntent;

import android.content.BroadcastReceiver;

import android.content.Context;

import android.content.Intent;

import android.graphics.Bitmap;

import android.graphics.BitmapFactory;

import android.widget.RemoteViews;

import com.example.graphics.R;

public class UpdateNotificationReceiver extends BroadcastReceiver{

public static int notId = 11; //与更新服务里的notId要不同,下载

public static String LoadAddress = "http://baidu.com";
//默认的apk下载网址

public static String VersionName = "1.2.0";
//新版本的版本名

@Override

public void onReceive(Context context, Intent intent) {

LoadAddress = intent.getStringExtra("address");

String abst= intent.getStringExtra("abstract");

Intent loadIntent = new Intent(context,UpdateNotificationService.class);

PendingIntent pi = PendingIntent.getService(context, 0,loadIntent, 0);

Notification foregroundNote;

Bitmap bigIcon = BitmapFactory.decodeResource(context.getResources(), R.drawable.ic_launcher);

RemoteViews bigView = new RemoteViews(context.getApplicationContext().getPackageName(),

R.layout.notification_layout_big);

bigView.setTextViewText(R.id.tv_versionAbstract, absts);

Notification.Builder mNotifyBuilder = new Notification.Builder(context);

foregroundNote = mNotifyBuilder.setContentTitle("某某版本更新,点击下载")

.setContentText("某某版本更新")

.setSmallIcon(R.drawable.ic_launcher)

.setTicker("某某版本更新")

.setLargeIcon(bigIcon)

.build();

foregroundNote.bigContentView = bigView;

foregroundNote.setLatestEventInfo(context, "某某版本更新,点击下载", abst, pi);

NotificationManager mNotifyManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);

mNotifyManager.notify(notId, foregroundNote);

}

}

下载要在服务中进行,服务类的代码如下

package com.example.update;

import java.io.File;

import android.app.Notification;

import android.app.NotificationManager;

import android.app.Service;

import android.content.Context;

import android.content.Intent;

import android.net.Uri;

import android.os.Environment;

import android.os.IBinder;

import com.example.graphics.R;

public class UpdateNotificationService extends Service{

private String DownloadUrl ;
//下载地址

private String loadApkPath ;
//apk文件路径

private String Path ; //APK保存路径

private String apkName; //应用名称

private NotificationManager notManager ;

private Notification notification ;

private int notId = 12; //与更新广播里的notId要不同

@Override

public IBinder onBind(Intent intent) {

// TODO Auto-generated method stub

return null;

}

@Override

public int onStartCommand(Intent intent, int flags, int startId) {

DownloadUrl = UpdateNotificationReceiver.LoadAddress;

apkName = "taobao"+UpdateNotificationReceiver.VersionName+".apk";

Path = Environment.getExternalStorageDirectory()+"/data/data/Apk";

File file2 = new File(Path);

if(!file2.exists())

file2.mkdirs();

loadApkPath = Path + apkName;

File file = new File(loadApkPath);

if(file.exists()){

file.delete();

}

notManager = (NotificationManager) UpdateNotificationService.this.getSystemService(Context.NOTIFICATION_SERVICE);

notManager.cancel(UpdateNotificationReceiver.notId); //取消广播里,点击下载的通知

notification = new Notification();

notification.icon = R.drawable.ic_launcher;

notification.setLatestEventInfo(this, "某某版本更新,下载中", "0%", null);

notManager.notify(notId,notification);

downLoadApk(); //开始下载apk

return super.onStartCommand(intent, flags, startId);

}

/**

* 下载apk,使用afinal框架,注意导入jar包

*

*/

protected void downLoadApk() {

FinalHttp fh = new FinalHttp();

fh.download(DownloadUrl, loadApkPath,

new AjaxCallBack<File>() {

/**

* 下载完成

* @param t apk文件

*/

@Override

public void onSuccess(File t) {

notManager.cancel(notId);

if(t.exists() && t.length() > 0){

//启动安装

Intent intent = new Intent();

intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

intent.setAction("android.intent.action.VIEW");

intent.addCategory("android.intent.category.DEFAULT");

intent.setDataAndType(Uri.fromFile(t),

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

startActivity(intent);

}

super.onSuccess(t);

}

/**

* 下载中

* @param count 文件总长度

* @param current 当前下载长度

*/

@Override

public void onLoading(long count, long current) {

//更新下载进度

notification.setLatestEventInfo(NotificationService.this, "某某版本更新", "下载进度 "+(int)(((double)current/count)*100)+"%", null);

notManager.notify(notId,notification);

super.onLoading(count, current);

}

});

}

}

现在代码基本已经全了,但是不要忘了,方法中我们经常会用到一个对象,我们的对象还没有创建,接下来是对象类

package com.example.update;

import java.io.Serializable;

public class VersionBean implements Serializable{

private String version_address;

private String version_abstract;

public VersionBean(){}

public VersionBean(String vAddress,String vAbstract){

this.version_address = vAddress;

this.version_abstract = vAbstract;

}

public String getVersion_address() {

return version_address;

}

public void setVersion_address(String version_address) {

this.version_address = version_address;

}

public String getVersion_abstract() {

return version_abstract;

}

public void setVersion_abstract(String version_abstract) {

this.version_abstract = version_abstract;

}

}

写到这里,主要类已经写完了,但是是不是觉得还缺点什么?如果你代码只是这样写,在实际操作中,会无法实现现在,因为我们的服务和广播还没有注册,否则android不会启动服务和广播,这里注册的代码就不写了,大家自己写吧。

由于第一次写博文,水平有限,这些代码也是别人教我的,感谢团队中不断教我的同事们,也希望我这篇简答的代码对大家有用,最后是源码的下载路径:
http://pan.baidu.com/s/1hq2BSG0。希望大家多动提出宝贵意见
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐