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

来源:互联网 发布:查班车的软件 编辑:程序博客网 时间:2024/05/16 04:06
此处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;//当前版本versionCodeprivate int mServerVersionCode;//服务器版本versionCodeprivate Handler mHandler = new Handler(){public void handleMessage(Message msg) {compareVersionCoder(mCurrentVersionCode,msg.arg1);};};@Overridepublic void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.main);try {mCurrentVersionCode = getCurrentVersionCode();} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}new Thread(new Runnable() {@Overridepublic void run() {// TODO Auto-generated method stubMessage 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() {@Overridepublic 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() {@Overridepublic 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 blocke.printStackTrace();} catch (Exception e) {// TODO Auto-generated catch blocke.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 blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}return null;}@Overridepublic void onClick(View v) {// TODO Auto-generated method stubNotificationManager 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";@Overridepublic IBinder onBind(Intent intent) {// TODO Auto-generated method stubreturn null;}private String titleId; private File updateFile = null;//文件存储 //通知栏private NotificationManager updateNotificationManager = null;private Notification updateNotification = null;//通知栏跳转Intentprivate Intent updateIntent = null;private PendingIntent updatePendingIntent = null;private String updateurl;RemoteViews contentView;@Overridepublic 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 {@Overrideprotected void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.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并finishpublic 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 stubLog.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();}}}

0 0
原创粉丝点击