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

Android软件自动更新,通知栏显示,项目源码

2015-03-29 10:40 731 查看
此处json解析使用的是阿里的FastJson
package com.szy.update;

/**
* 全局控制
* @author LSC
*
*/
public class Config {

//测试网址
public static final String BASE_URL = "http://127.0.0.1";

//版本更新,从服务器获取apk信息
public static final String UPDATE_JSON_URL = BASE_URL + "/version/bh_apk_version.json";
//apk存放的文件夹,
public static final String APK_STROAGE_DIR = "/sdcard/update";
//apk存放位置,在实际应用中apk的名字最好固定下来
public static final String APK_STROAGE_ADDRESS = APK_STROAGE_DIR + "/MFTicketTerminalCommonBlackHand-1.7.0.apk";
}



<span style="color:#ff0000;">此处是主要类,启动次此类时请求服务器</span>
 
package com.szy.update;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

/**
* auto updateVersion
* @author LSC
*
*/
public class MainActivity extends Activity implements OnClickListener{

/*
* 从服务器获取到的版本信息,json格式
* http://127.0.0.1/version/bh_apk_version.json * {
"apk_version": "7",
"apk_md5": "e55f52386e109abba75f4cc83d3629dd",
"apk_url": "http://127.0.0.1/downloads/MFTicketTerminalCommonBlackHand-1.7.0.apk",
"base_url": "http://127.0.0.1"
}*/
private String apkDownloadUrl;//apk下载地址

private DownloadApkAndInstall mDownloadApkInstall;

private Button updateServiceBtn;

private int mCurrentVersionCode;//当前版本versionCode
private int mServerVersionCode;//服务器版本versionCode

private Handler mHandler = new Handler(){
public void handleMessage(Message msg) {
compareVersionCoder(mCurrentVersionCode,msg.arg1);
};
};

@Override
public void onCreate(Bundle savedInstanceState){

super.onCreate(savedInstanceState);
setContentView(R.layout.main);
try {
mCurrentVersionCode = getCurrentVersionCode();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
new Thread(new Runnable() {

@Override
public void run() {
// TODO Auto-generated method stub
Message msg = new Message();
mServerVersionCode = Integer.valueOf(getServerVersionCode(
getJsonHttpURLConnection(Config.UPDATE_JSON_URL)));
msg.arg1 = mServerVersionCode;
mHandler.sendMessage(msg);
}
}).start();
initView();
}

public void initView(){
updateServiceBtn = (Button) findViewById(R.id.btnUpdate);

updateServiceBtn.setOnClickListener(this);
}

/*
* 获取当前程序的版本号  VersionCode
*/
int getCurrentVersionCode() throws Exception{

PackageManager packageManager = getPackageManager();
PackageInfo packInfo = packageManager.getPackageInfo(getPackageName(), 0);

return packInfo.versionCode;
}

/*
* 获取当前程序的  versionName
*/
String getCurrentVersionName() throws Exception{

PackageManager packageManager = getPackageManager();
PackageInfo packInfo = packageManager.getPackageInfo(getPackageName(), 0);

return packInfo.versionName;
}

/**
* get apk name
* @param context
* @return
*/
public static String getAppName(Context context) {

String verName = context.getResources()
.getText(R.string.app_name).toString();

return verName;
}

/**
* get server VersionCode and apkDownloadUrl
* @return
*/
private String getServerVersionCode (String jsonByNet){

JSONObject response = JSON.parseObject(jsonByNet);
String serverVersionCode = response.getString("apk_version");
apkDownloadUrl = response.getString("apk_url");

return serverVersionCode;
}

/**
* compare serverVersionCode with currentVersionCode
*
* Whether or not to update
*/
public void compareVersionCoder(int currentVersionCode,final int serverVersionCode){

try {
if(serverVersionCode > currentVersionCode){
new AlertDialog.Builder(this).setTitle("提示").setMessage("您的版本过低,我们建议您更新到最新的版本。")
.setPositiveButton("sure", new DialogInterface.OnClickListener() {

@Override
public void onClick(DialogInterface dialog, int which) {
mDownloadApkInstall = new DownloadApkAndInstall(MainActivity.this);
mDownloadApkInstall.updateVersion(mServerVersionCode, MainActivity.this, apkDownloadUrl);
dialog.dismiss();
}
}).setNegativeButton("next update", new DialogInterface.OnClickListener() {

@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
}).show();

}else{
Toast.makeText(this, "Is currently the latest version", Toast.LENGTH_LONG).show();
}
} catch (NumberFormatException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

/**
* get json String
* @param jsonURL
* @return
*/
public String getJsonHttpURLConnection(String jsonURL){
InputStream is = null;
try {
URL url = new URL(jsonURL);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(5000);
conn.setConnectTimeout(5000);
if(conn.getResponseCode() == 200){
//获取数据
is = conn.getInputStream();
BufferedReader buffer = new BufferedReader(new InputStreamReader(is,"utf-8"));
String inputLine = null;
StringBuffer sbContent = new StringBuffer();

while ((inputLine = buffer.readLine()) != null){
sbContent.append(inputLine);
}
System.out.println(sbContent.toString());
return sbContent.toString();
}else{
Toast.makeText(this, "连接服务器失败", Toast.LENGTH_LONG).show();
}
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}

@Override
public void onClick(View v) {
// TODO Auto-generated method stub
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
Notification notification = new Notification(R.drawable.notify_icon, "poap", System.currentTimeMillis());
Intent intent = new Intent(this,NotificationActivity.class);
PendingIntent pi = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
notification.setLatestEventInfo(this, "This is content title", "This is content text", pi);
manager.notify(1, notification);
Log.d("MainActivity","Thread id is "+Thread.currentThread().getId());
}

}


此处是service,大家不要忘记注册service和activity,Android的四大组件在清单文件Manifest.xml都需要注册的,也不要忘了设置两个权限

package com.szy.update;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.net.Uri;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.util.Log;
import android.widget.RemoteViews;
import android.widget.Toast;

public class UpdateService extends Service {

private static final String TAG = "UpdateService";

@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}

private String titleId;

private File updateFile = null;//文件存储

//通知栏
private NotificationManager updateNotificationManager = null;
private Notification updateNotification = null;
//通知栏跳转Intent
private Intent updateIntent = null;
private PendingIntent updatePendingIntent = null;
private String updateurl;
RemoteViews contentView;

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

titleId = intent.getStringExtra("titleId");
updateurl=intent.getStringExtra("updateurl");
updateFile = new File(Config.APK_STROAGE_ADDRESS);
updateNotificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
updateNotification = new Notification(R.drawable.notify_icon, titleId+"开始下载", System.currentTimeMillis());

updateIntent = new Intent(UpdateService.this,Notification.class);
updatePendingIntent = PendingIntent.getActivity(this,0,updateIntent,PendingIntent.FLAG_CANCEL_CURRENT);
//
updateNotification.setLatestEventInfo(this,"***","0%",updatePendingIntent);

contentView =new RemoteViews(this.getPackageName(),R.layout.notificationupdate);
contentView.setTextViewText(R.id.tvnow, "正在下载...");
contentView.setTextViewText(R.id.tvjingdu, "0%");
contentView.setProgressBar(R.id.progress_horizontal, 100, 0, false);
updateNotification.contentView=contentView;
//发出通知
updateNotificationManager.notify(1,updateNotification);
//开启一个新的线程下载,如果使用Service同步下载,会导致ANR问题,Service本身也会阻塞
new Thread(new updateRunnable()).start();//这个是下载的重点,是下载的过程

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

private Handler updateHandler = new  Handler(){
@Override
public void handleMessage(Message msg) {

switch (msg.what) {
case DOWNLOAD_COMPLETE:
//点击安装PendingIntent
Boolean iswanzheng=Utils.getUninatllApkInfo(UpdateService.this, updateFile.toString());
if(iswanzheng){
Uri uri = Uri.fromFile(updateFile);
Intent installIntent = new Intent(Intent.ACTION_VIEW);
installIntent.setDataAndType(uri, "application/vnd.android.package-archive");
updatePendingIntent = PendingIntent.getActivity(UpdateService.this, 0, installIntent, 0);
updateNotification.defaults = Notification.DEFAULT_SOUND;//铃声提醒
updateNotification.setLatestEventInfo(UpdateService.this, "***", "下载完成,点击安装。", updatePendingIntent);
updateNotificationManager.notify(1, updateNotification);

installIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getApplicationContext().startActivity(installIntent);
}else{
Toast.makeText(UpdateService.this, "下载包不完整,请重新下载...", Toast.LENGTH_SHORT).show();
}
//停止服务
stopSelf();
break;
case DOWNLOAD_FAIL:
//下载失败
updateNotification.setLatestEventInfo(UpdateService.this, "***", "下载失败,可能是网络 不好。", updatePendingIntent);
updateNotificationManager.notify(1, updateNotification);
stopSelf();
break;
default:
stopSelf();
}

}
};

public class updateRunnable implements Runnable{

Message message = updateHandler.obtainMessage();
public void run() {
message.what = DOWNLOAD_COMPLETE;
try{
if(!updateFile.exists()){
updateFile.createNewFile();
}

//增加权限;
long downloadSize = downloadUpdateFile(updateurl,updateFile);
if(downloadSize>0){
//下载成功
updateHandler.sendMessage(message);
}
}catch(Exception ex){
ex.printStackTrace();
message.what = DOWNLOAD_FAIL;
//下载失败
updateHandler.sendMessage(message);
}
}
}

public long downloadUpdateFile(String downloadUrl, File saveFile) throws Exception {
//这样的下载代码很多,我就不做过多的说明
int downloadCount = 0;
int currentSize = 0;
long totalSize = 0;
int updateTotalSize = 0;

HttpURLConnection httpConnection = null;
InputStream is = null;
FileOutputStream fos = null;

try {
URL url = new URL(downloadUrl);
httpConnection = (HttpURLConnection)url.openConnection();
httpConnection.setRequestProperty("User-Agent", "PacificHttpClient");
if(currentSize > 0) {
httpConnection.setRequestProperty("RANGE", "bytes=" + currentSize + "-");
}
httpConnection.setConnectTimeout(10000);
httpConnection.setReadTimeout(20000);
updateTotalSize = httpConnection.getContentLength();
if (httpConnection.getResponseCode() == 404) {
throw new Exception("fail!");
}
is = httpConnection.getInputStream();
fos = new FileOutputStream(saveFile, false);
byte buffer[] = new byte[4096];
int readsize = 0;
while((readsize = is.read(buffer)) > 0){
fos.write(buffer, 0, readsize);
totalSize += readsize;
//为了防止频繁的通知导致应用吃紧,百分比增加4才通知一次
if((downloadCount == 0)||(int) (totalSize*100/updateTotalSize)-4>downloadCount){
downloadCount += 4;
//updateNotification.setLatestEventInfo(UpdateService.this, "正在下载...", (int)totalSize*100/updateTotalSize+"%", updatePendingIntent);
contentView.setProgressBar(R.id.progress_horizontal, 100, downloadCount, false);
contentView.setTextViewText(R.id.tvjingdu, (int)totalSize*100/updateTotalSize+"%");
updateNotificationManager.notify(1, updateNotification);
}
}
}catch(Exception ex){
ex.printStackTrace();
Log.e(TAG, ex.toString());
} finally {
if(httpConnection != null) {
httpConnection.disconnect();
}
if(is != null) {
is.close();
}
if(fos != null) {
fos.close();
}
}
return totalSize;
}

//下载状态
private final static int DOWNLOAD_COMPLETE = 0;
private final static int DOWNLOAD_FAIL = 1;

}


当在通知栏点击时,会跳转到此类

package com.szy.update;

import android.app.Activity;
import android.os.Bundle;

public class NotificationActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.notification_download);
}
}


此类为工具类

package com.szy.update;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Environment;
import android.util.Log;
import android.widget.Toast;

public class Utils {

private static final String TAG = "Utils";

public static String digits = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLIMNOPQRSTUVWXYZ~!@#$%^&*()_+{}:\'|<>?-=[];\"\\,./";

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

// 添加Activity到容器中
public static void addActivity(Activity activity) {
if (activityList != null && activity != null) {
activityList.add(activity);
}
}

// 遍历所有Activity并finish

public static void exit() {

for (Activity activity : activityList) {
if (activity != null) {
activity.finish();
}
}
activityList.clear();

}

/**
* SDCard 根目录
*
* @return
*/
public static String getSDCardRootPath() {
File sdCardDir = null;
boolean sdcardExist = Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
if (sdcardExist) {
sdCardDir = Environment.getExternalStorageDirectory();
StringBuffer buffer = new StringBuffer();
buffer.append(sdCardDir);
buffer.append(File.separator);
buffer.append("guideBuyTicket");
return buffer.toString();
}
return null;
}

public static SharedPreferences getSP() {
//		SharedPreferences sp = CrashApplication.app.getSharedPreferences(Config.CONFIG_FILE_NAME, Context.MODE_PRIVATE);
//		return sp;
return null;
}

public static void updateVersion(String apkMd5, String versionName, Context context, String url) {
if (Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) {

File updateDir = new File(Environment.getExternalStorageDirectory(), "");
File updateFile = new File(updateDir.getPath(), versionName + ".apk");

if (updateFile.exists()) {

if (Utils.getUninatllApkInfo(context, updateFile.getAbsolutePath())) {
Uri uri = Uri.fromFile(updateFile);
Intent installIntent = new Intent(Intent.ACTION_VIEW);
installIntent.setDataAndType(uri, "application/vnd.android.package-archive");
context.startActivity(installIntent);
} else {
Intent updateIntent = new Intent(context, UpdateService.class);
updateIntent.putExtra("titleId", R.string.app_name);
updateIntent.putExtra("updateurl", url);
updateIntent.putExtra("newversion", versionName);
context.startService(updateIntent);
Toast.makeText(context, "下载包不完整,正在下载...!", Toast.LENGTH_SHORT).show();
}

} else {
Intent updateIntent = new Intent(context, UpdateService.class);
updateIntent.putExtra("titleId", R.string.app_name);
updateIntent.putExtra("updateurl", url);
updateIntent.putExtra("newversion", versionName);
context.startService(updateIntent);
}

} else {

Toast.makeText(context, "你没有sd卡,请安装", Toast.LENGTH_SHORT).show();
}
}

/**
* 判断未安装apk包的完整性
*
* @param context
* @param filePath
* @return
*/
public static boolean getUninatllApkInfo(Context context, String filePath) {
boolean result = false;
try {
PackageManager pm = context.getPackageManager();
Log.e("archiveFilePath", filePath);
PackageInfo info = pm.getPackageArchiveInfo(filePath, PackageManager.GET_ACTIVITIES);
String packageName = null;
if (info != null) {
result = true;
}
} catch (Exception e) {
result = false;

e.printStackTrace();

}
return result;

}

public static String MD5(String inStr) {
MessageDigest md5 = null;
try {
md5 = MessageDigest.getInstance("MD5");
} catch (Exception e) {
System.out.println(e.toString());
e.printStackTrace();
return "";
}
char[] charArray = inStr.toCharArray();
byte[] byteArray = new byte[charArray.length];

for (int i = 0; i < charArray.length; i++)
byteArray[i] = (byte) charArray[i];
byte[] md5Bytes = md5.digest(byteArray);
StringBuffer hexValue = new StringBuffer();
for (int i = 0; i < md5Bytes.length; i++) {
int val = ((int) md5Bytes[i]) & 0xff;
if (val < 16)
hexValue.append("0");
hexValue.append(Integer.toHexString(val));
}
return hexValue.toString();

}

/**
* 用md5判断apk是否完整
*
* @param apkMd5
* @param path
* @return
*/
// public static boolean isCompleByMd5(String apkMd5, String path) {
// String apkStr = readString(path);
// String curApkMd5 = MD5(apkStr);
// LogUtil.i(TAG, "curApkMd5====" + curApkMd5);
// if (apkMd5.equals(curApkMd5)) {
// return true;
// }
// return false;
// }

/**
* 以字节为单位读取文件,常用于读二进制文件,如图片、声音、影像等文件。 当然也是可以读字符串的。
*/
/* 貌似是说网络环境中比较复杂,每次传过来的字符是定长的,用这种方式? */
public static String readString(String path) {
try {
// FileInputStream 用于读取诸如图像数据之类的原始字节流。要读取字符流,请考虑使用 FileReader。
FileInputStream inStream = new FileInputStream(path);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int length = -1;

while ((length = inStream.read(buffer)) != -1) {
bos.write(buffer, 0, length);
// .write方法 SDK 的解释是 Writes count bytes from the byte array
// buffer starting at offset index to this stream.
// 当流关闭以后内容依然存在
}
bos.close();
inStream.close();
return bos.toString();
// 为什么不一次性把buffer得大小取出来呢?为什么还要写入到bos中呢? return new(buffer,"UTF-8")
// 不更好么?
// return new String(bos.toByteArray(),"UTF-8");
} catch (Exception e) {

}
return null;
}

/**
* 验证手机号码
*
* @param mobiles
* @return
*/
public static boolean isMobileNO(String mobiles) {
boolean flag = false;
try {
Pattern p = Pattern.compile("^1[34578][0-9]{9}$");
Matcher m = p.matcher(mobiles);
flag = m.matches();
} catch (Exception e) {
flag = false;
}
return flag;
}

/**
* 验证身份证号码
*
* @param mobiles
* @return
*/
public static boolean isIdCard(String mobiles) {
boolean flag = false;
try {
Pattern p = Pattern.compile("^(\\d{14}|\\d{17})(\\d|[xX])$");
Matcher m = p.matcher(mobiles);
flag = m.matches();
} catch (Exception e) {
flag = false;
}
return flag;
}

}


package com.szy.update;

import java.io.File;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Environment;
import android.util.Log;
import android.widget.Toast;

public class DownloadApkAndInstall {

private Context mContext;

private PackageManager pm;

public DownloadApkAndInstall(Context context){
this.mContext = context;
pm = context.getPackageManager();
}

//打开APK程序代码

private void openFile(File file) {
// TODO Auto-generated method stub
Log.e("OpenFile", file.getName());
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setAction(android.content.Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(file),
"application/vnd.android.package-archive");
mContext.startActivity(intent);
}
/**
* get exist apk versionCode
* @param apkPath
* @return
*/
private int getApkVersionCode(String apkPath) {
PackageInfo pi = pm.getPackageArchiveInfo(apkPath,
PackageManager.GET_ACTIVITIES);
int versionCode = 1;
if (pi != null) {
versionCode = pi.versionCode;
}
return versionCode;
}

/**
* 判断未安装apk包的完整性
*
* @param context
* @param filePath
* @return
*/
public boolean getUninatllApkInfo(Context context, String filePath) {
boolean result = false;
try {
PackageManager pm = context.getPackageManager();
Log.e("archiveFilePath", filePath);
PackageInfo info = pm.getPackageArchiveInfo(filePath, PackageManager.GET_ACTIVITIES);
@SuppressWarnings("unused")
String packageName = null;
if (info != null) {
result = true;
}
} catch (Exception e) {
result = false;

e.printStackTrace();

}
return result;

}

public void updateVersion(int serverVersionCode, Context context, String url) {
if (Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) {

File updateDir = new File(Config.APK_STROAGE_DIR);
if(!updateDir.exists()){
updateDir.mkdirs();
}

File updateFile = new File(Config.APK_STROAGE_ADDRESS);

if (updateFile.exists()) {

if(getUninatllApkInfo(mContext, updateFile.toString())){

if (serverVersionCode > getApkVersionCode(updateFile.toString())) {

updateFile.delete();
Intent updateIntent = new Intent(context, UpdateService.class);
updateIntent.putExtra("titleId", "***");
updateIntent.putExtra("updateurl", url);
updateIntent.putExtra("updateFile",updateFile.toString());
//					updateIntent.putExtra("newversion", versionName);
context.startService(updateIntent);

} else {

System.out.println("此版本已存在");
openFile(updateFile);
return;
}

}else{

System.out.println("文件损坏");
updateFile.delete();
Intent updateIntent = new Intent(context, UpdateService.class);
updateIntent.putExtra("titleId", "***");
updateIntent.putExtra("updateurl", url);
updateIntent.putExtra("updateFile",updateFile.toString());
//					updateIntent.putExtra("newversion", versionName);
context.startService(updateIntent);

}

} else {

Intent updateIntent = new Intent(context, UpdateService.class);
updateIntent.putExtra("titleId", "***");
updateIntent.putExtra("updateurl", url);
updateIntent.putExtra("updateFile",updateFile.toString());
//				updateIntent.putExtra("newversion", versionName);
context.startService(updateIntent);

}

} else {

Toast.makeText(context, "你没有sd卡,请安装", Toast.LENGTH_SHORT).show();
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐