开发app 肯定要用到版本升级更新
对于小的bug一般都是使用热修复 对版本更新没有要求 所以还没研究 直接使用版本升级
大概思路就是 根据版本得code 或者版本名称之类得判断是否需要升级 如果需要就开启一个服务下载新版本 实现的流程就是在发现新版本后通过弹出提示框 提示下载 如果下载 会在手机通知栏有一个下载中得状态栏 效果一般 在下载完成后覆盖安装
import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; import android.annotation.SuppressLint; 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.Handler; import android.os.IBinder; import android.os.Message; import com.xgs.financepay.R; import com.xgs.utils.FileUtil; /*** * 升级服务 */ public class UpdateService extends Service { // public static final String Install_Apk = "Install_Apk"; /******** * download progress step *********/ private static final int down_step_custom = 3; private static final int TIMEOUT = 100 * 1000;// 超时 private static String down_url; private static final int DOWN_OK = 1; private static final int DOWN_ERROR = 0; private String app_name; private NotificationManager notificationManager; private Notification.Builder builder; @Override public IBinder onBind(Intent arg0) { return null; } @Override public int onStartCommand(Intent intent, int flags, int startId) { try { app_name = intent.getStringExtra("Key_App_Name"); down_url = intent.getStringExtra("Key_Down_Url"); } catch (Exception e) { Message message = new Message(); message.what = DOWN_ERROR; handler.sendMessage(message); } // create file,应该在这个地方加一个返回值的判断SD卡是否准备好,文件是否创建成功,等等! FileUtil.createFile(app_name); // if (FileUtil.isCreateFileSucess == true) { createNotification(); createThread(); // } else { // Toast.makeText(this, "请插入SD卡", Toast.LENGTH_SHORT) // .show(); // /*************** stop service ************/ // stopSelf(); // createNotification(); // createThread(); // } return super.onStartCommand(intent, flags, startId); } @SuppressLint("HandlerLeak") private final Handler handler = new Handler() { @SuppressWarnings("deprecation") @Override public void handleMessage(Message msg) { switch (msg.what) { case DOWN_OK: /***** 安装APK ******/ builder.setContentText("下载成功,正在安装"); builder.setAutoCancel(true); builder.getNotification().flags = Notification.FLAG_AUTO_CANCEL; notificationManager.notify(R.layout.notification_item, builder.getNotification()); installApk(); stopSelf(); break; case DOWN_ERROR: builder.setContentText("下载失败,请检查是否开启存储卡写入权限"); builder.setAutoCancel(true); builder.getNotification().flags = Notification.FLAG_AUTO_CANCEL; notificationManager.notify(R.layout.notification_item, builder.getNotification()); stopSelf(); /***stop service*****/ //onDestroy(); break; default: break; } } }; private void installApk() { /*********下载完成,点击安装***********/ Uri uri = Uri.fromFile(FileUtil.updateFile); Intent intent = new Intent(Intent.ACTION_VIEW); /**********加这个属性是因为使用Context的startActivity方法的话,就需要开启一个新的task**********/ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.setDataAndType(uri, "application/vnd.android.package-archive"); UpdateService.this.startActivity(intent); } public void createThread() { new DownLoadThread().start(); } private class DownLoadThread extends Thread { @Override public void run() { Message message = new Message(); try { long downloadSize = downloadUpdateFile(down_url, FileUtil.updateFile.toString()); if (downloadSize > 0) { message.what = DOWN_OK; handler.sendMessage(message); } } catch (Exception e) { message.what = DOWN_ERROR; handler.sendMessage(message); } } } public void createNotification() { builder = new Notification.Builder(this); //应用的图标 builder.setSmallIcon(R.mipmap.login_logo).setOngoing(false) .setContentText("正在下载安装包") .setContentTitle("标题"); builder.setAutoCancel(true); builder.setTicker("正在下载安装包"); builder.setProgress(100, 0, true); notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); notificationManager.notify(R.layout.notification_item, builder.getNotification()); } public long downloadUpdateFile(String down_url, String file) throws Exception { long down_step = down_step_custom;// 提示step long totalSize;// 文件总大小 long downloadCount = 0;// 已经下载好的大小 int updateCount = 0;// 已经上传的文件大小 InputStream inputStream; OutputStream outputStream; URL url = new URL(down_url); HttpURLConnection httpURLConnection = (HttpURLConnection) url .openConnection(); httpURLConnection.setConnectTimeout(TIMEOUT); httpURLConnection.setReadTimeout(TIMEOUT); // 获取下载文件的size totalSize = httpURLConnection.getContentLength(); if (httpURLConnection.getResponseCode() == 404) { throw new Exception("download fail!"); } inputStream = httpURLConnection.getInputStream(); outputStream = new FileOutputStream(file, false);// 文件存在则覆盖掉 byte buffer[] = new byte[1024]; int readsize = 0; while ((readsize = inputStream.read(buffer)) != -1) { outputStream.write(buffer, 0, readsize); downloadCount += readsize;// 时时获取下载到的大小 if (updateCount == 0 || (downloadCount * 100 / totalSize - down_step) >= updateCount) { updateCount += down_step; builder.setProgress(100, updateCount, true); notificationManager.notify(R.layout.notification_item, builder.getNotification()); } } if (httpURLConnection != null) { httpURLConnection.disconnect(); } inputStream.close(); outputStream.close(); return downloadCount; } @Override public void onDestroy() { super.onDestroy(); } }
<!-- 升级服务 --> <service android:name=".service.UpdateService" />
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:padding="3dp" > <ImageView android:id="@+id/notificationImage" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@android:drawable/stat_sys_download" android:paddingLeft="16dp"/> <TextView android:id="@+id/notificationTitle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_toRightOf="@id/notificationImage" android:paddingLeft="26dp" android:textColor="#FFFFFFFF" /> <!-- android:textColor="#FF000000" --> <TextView android:id="@+id/notificationPercent" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/notificationImage" android:paddingTop="2dp" android:textColor="#FFFFFFFF" android:paddingLeft="16dp"/> <ProgressBar android:id="@+id/notificationProgress" style="?android:attr/progressBarStyleHorizontal" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@id/notificationTitle" android:layout_alignParentRight="true" android:layout_alignTop="@id/notificationPercent" android:layout_below="@id/notificationTitle" android:paddingLeft="26dp" android:paddingRight="3dp" android:paddingTop="2dp" /> </RelativeLayout>
/** * 类描述:FileUtil */ public class FileUtil { public static File updateDir = null; public static File updateFile = null; /*********** * 保存升级APK的目录 ***********/ public static final String aaaa = "aaaa"; public static boolean isCreateFileSucess; /** * 方法描述:createFile方法 * * @return * @see FileUtil */ public static void createFile(String app_name) { // if (Environment.MEDIA_MOUNTED.equals(Environment // .getExternalStorageState())) { //该方法为判断是否有外挂路径 但是有外挂无sd卡路径 无法创建 if (!TextUtils.isEmpty(Environment.getExternalStorageDirectory().toString())) { updateDir = new File(Environment.getExternalStorageDirectory() + "/" + aaaa + "/"); isCreateFileSucess = true; // updateDir = new File(Environment.getDataDirectory() // + "/" + aaaa + "/");// 获得根目录/data 内部存储路径 data路径读写失败 是不是权限问题? if (!updateDir.exists()) { updateDir.mkdirs(); } updateFile = new File(updateDir + "/" + app_name + ".apk"); Log.i("updateDir", "" + updateDir); if (!updateFile.exists()) { try { updateFile.createNewFile(); } catch (IOException e) { isCreateFileSucess = false; e.printStackTrace(); } } } else { updateDir = new File(Environment.getDataDirectory() + "/" + aaaa + "/");// 获得根目录/data 内部存储路径 data路径读写失败 是不是权限问题? if (!updateDir.exists()) { updateDir.mkdirs(); } updateFile = new File(updateDir + "/" + app_name + ".apk"); Log.i("updateDir", "" + updateDir); if (!updateFile.exists()) { try { updateFile.createNewFile(); } catch (IOException e) { isCreateFileSucess = false; e.printStackTrace(); } } } } public static boolean inputStreamToOutputStream(InputStream input, OutputStream output) { BufferedOutputStream out = null; BufferedInputStream in = null; in = new BufferedInputStream(input, 8 * 1024); out = new BufferedOutputStream(output, 8 * 1024); int b; try { while ((b = in.read()) != -1) { out.write(b); } return true; } catch (IOException e) { e.printStackTrace(); } finally { try { if (out != null) out.close(); if (in != null) in.close(); } catch (final IOException e) { e.printStackTrace(); } } return false; } public static String inputStreamToString(InputStream in) { String result = ""; if (null != in) { InputStreamReader ir = null; BufferedReader br = null; StringBuffer sb = new StringBuffer(); try { ir = new InputStreamReader(in); br = new BufferedReader(ir); String line; while ((line = br.readLine()) != null) sb.append("/n").append(line); if (result.length() > 0) result = result.substring("/n".length()); } catch (IOException e) { e.printStackTrace(); } finally { try { if (ir != null) ir.close(); if (br != null) br.close(); } catch (IOException e) { e.printStackTrace(); } } } return result; } public static InputStream byteToInputStream(byte[] bytes) { ByteArrayInputStream bais = new ByteArrayInputStream(bytes); return bais; } //检测sd卡是否可用 public static boolean checkSDcardValid() { String sdStatus = Environment.getExternalStorageState(); if (!sdStatus.equals(Environment.MEDIA_MOUNTED)) { Log.e("fileutil", "sd卡不可用!"); return false; } return true; } //判断文件夹是否创建成功 public static boolean createDir() { File dir = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/aaaa/"); Log.d("fileutil", "文件夹路径:" + dir.getAbsolutePath()); if (!dir.exists()) { if (!dir.mkdir()) { Log.e("fileutil", "创建文件夹失败!"); return false; } } return true; }}