Android app版本升級的一個簡單實現
阿新 • • 發佈:2018-11-07
夢想會被現實磨滅,希望我能堅持的長久!
1升級原理
build.gradle 中 versionCode 1 , versionName “1.0.0” 是升級的關鍵,versionCode是個int,versionName是個String,其中versionCode每次要升級版本都需要+1,VersionName是給使用者看的,讓使用者知道當前版本。
升級原理:
從伺服器獲取升級資訊,包括versionCode,versionName,升級下載app的地址url,是否強制升級,升級的資訊等,然後通過比較本地app的versionCode,決定是否下載app進行升級。
2一個簡單的升級示例
//獲取versionCode
public static int getVersionCode(Context context) {
int version = 0;
try {
PackageManager packageManager = context.getPackageManager();
PackageInfo packInfo = packageManager.getPackageInfo(context.getPackageName(), 0);
version = packInfo. versionCode;
} catch (Exception e) {
e.printStackTrace();
}
return version;
}
public class UpdateHelper {
private static final int ALREADY_NEW = 1;
private static final int SHOWUPDATE = 2;
private static final int INSTALLUPDATE = 3;
private final String savePath = Environment.getExternalStorageDirectory()
.getPath() + "/updateload";
private UpdateInfoData mUpdateInfoData;
private File mDownloadedFile = null;
private final String defaultPackageName = "testapp.apk";
private Context mContext = null;
private boolean mShowToast = false;
public UpdateHelper(Context context, boolean showToast) {
mContext = context;
mShowToast = showToast;
mUpdateInfoData = new UpdateInfoData("0",0,"0","","");
}
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case ALREADY_NEW:
if ( mDownloadedFile != null ) {
//刪除上次已下載的檔案
if ( mDownloadedFile.exists() ) {
if (! mDownloadedFile.delete() ) {
mDownloadedFile.deleteOnExit();
}
}
}
if (mShowToast) {
Toast.makeText(mContext,
"當前已是最新版本.", Toast.LENGTH_SHORT)
.show();
}
break;
case SHOWUPDATE:
showUpdateDialog();
break;
case INSTALLUPDATE:
installUpdate();
break;
}
}
};
public void checkUpdate(final boolean reportResult) {
try {
new Thread(new Runnable() {
@Override
public void run() {
boolean isNewVersionAvailable = false;
if (getServerVersionInfo()) {
String lastestVersionCode = "0";
if ( mUpdateInfoData != null ) {
if (mUpdateInfoData.getLastestVersionCode() != null) {
lastestVersionCode = mUpdateInfoData.getLastestVersionCode();
}
if (Integer.parseInt(lastestVersionCode) > UpdateUtil.getVersionCode(mContext))
isNewVersionAvailable = true;
}
}
if (isNewVersionAvailable) {
Message msg = new Message();
msg.what = SHOWUPDATE;
handler.sendMessage(msg);
} else {
if (reportResult) {
Message msg = new Message();
msg.what = ALREADY_NEW;
handler.sendMessage(msg);
}
}
}
}).start();
} catch (NumberFormatException e) {
e.printStackTrace();
}
}
public boolean getServerVersionInfo() {
//是否有可用版本;
//從網路獲取升級資訊
Call<UpdateResultData> call = null ;//ServiceFactory.newApiService().getUpdateInfo(paramsMap);
try {
Response<UpdateResultData> updateInfoResponse = call.execute();
if (updateInfoResponse != null && updateInfoResponse.isSuccessful()) {
UpdateResultData resultData = updateInfoResponse.body();
if(resultData != null && resultData.getErrno() == 0){
UpdateInfoData info = updateInfoResponse.body().getResult();
if (info != null) {
mUpdateInfoData = info;
}else{
return false;
}
}
} else {
return false;
}
} catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}
//可以換成retrofit 下載更簡單
public boolean downloadFile(ProgressDialog pd) {
URL url;
try {
String urlStr = "";
if (mUpdateInfoData != null && mUpdateInfoData.getUrl() != null) {
urlStr = mUpdateInfoData.getUrl();
}
url = new URL(urlStr);
HttpURLConnection conn;
conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(10000);
pd.setMax(conn.getContentLength());
InputStream is = conn.getInputStream();
String packageName = urlStr.substring(urlStr.lastIndexOf("/"));
if (!packageName.endsWith("apk")) {
packageName = defaultPackageName;
}
mDownloadedFile = new File(savePath, packageName);
FileOutputStream fos = new FileOutputStream(mDownloadedFile);
BufferedInputStream bis = new BufferedInputStream(is);
byte[] buffer = new byte[1024];
int len;
int total = 0;
while ((len = bis.read(buffer)) != -1) {
fos.write(buffer, 0, len);
total += len;
//update progress
pd.setProgress(total);
}
fos.close();
bis.close();
is.close();
return true;
} catch (MalformedURLException e) {
e.printStackTrace();
return false;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
public void InstallAPK(Context context) {
if ( context == null ) {
return;
}
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(this.mDownloadedFile), "application/vnd.android.package-archive");
context.startActivity(intent);
}
//顯示更新dialog
private void showUpdateDialog() {
try {
Builder builder = new Builder(mContext);
builder.setIcon(R.mipmap.ic_launcher);
builder.setTitle("發現新版本");
builder.setMessage(mUpdateInfoData.getContent().replaceAll("\\\\n","\n"));
builder.setCancelable(false);
builder.setPositiveButton(
"立即更新",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
final ProgressDialog pd = new ProgressDialog(mContext);
try {
pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
pd.setCancelable(false);
pd.setMessage("正在下載...");
pd.show();
new Thread(new Runnable() {
@Override
public void run() {
boolean isSuccess = downloadFile(pd);
if (isSuccess) {
pd.dismiss();
Message msg = new Message();
msg.what = INSTALLUPDATE;
handler.sendMessage(msg);
} else {
if (pd != null) {
pd.dismiss();
}
Toast.makeText(mContext, "下載失敗,請檢查你的網路", Toast.LENGTH_SHORT).show();
}
}
}).start();
} catch (Exception e) {
e.printStackTrace();
}
}
}
);
builder.setNegativeButton( mUpdateInfoData.getForce() == 1 ? "退出應用":"暫不更新", (( dialog, which ) -> {
if ( mUpdateInfoData != null ) {
if ( mUpdateInfoData.getForce() == 1 ) {
Process.killProcess( Process.myPid() );
} else {
dialog.dismiss();
}
}
}) );
AlertDialog dialog = builder.create();
dialog.show();
// dialog.getButton(AlertDialog.BUTTON_POSITIVE).setTextColor(Color.BLUE);
// dialog.getButton(DialogInterface.BUTTON_NEGATIVE).setTextColor(Color.BLACK);
} catch (Exception e) {
e.printStackTrace();
}
}
private void installUpdate() {
InstallAPK(mContext);
}
public void destroyHelper() {
try {
handler.removeCallbacksAndMessages(null);
handler = null;
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class UpdateInfoData implements Serializable {
private String lastestVersionName;
// 1 for force, 0 for not.
private int force;
private String lastestVersionCode;
private String url;
private String content;
}
點選之後利用ProgressDialog更新下載進度,之後完成安裝。
如果想更好的控制dialog的生命週期,或者自定義升級提示框的樣式,可以利用dialogFragment實現。
3關於強制升級
強制升級的實現方法:
使用者不升級無法使用,要嗎升級要麼退出應用,實現方式彈出的升級提示框沒有取消升級按鈕,或者有不升級按鈕點選之後是退出應用。
一般不需要強制升級這個功能,但是有時由於後端介面升級或者資料結構改變,或者重大功能上線都可能需要強制升級功能,但儘量平穩的升級。