編輯:關於Android編程
一、更新軟件的准備
在線更新軟件的話需要我們有簽名的應用,我們需要把簽過名之後的軟件放入到服務器中,我的如下:
其中apk是有簽名的更新版本!
updateinfo.html代碼如下:
{version:2.0,description:有全新版本,請下載!,apkurl:hhtp://172.23.252.89:8080/MobileSafe2.0.apk}
二、具體客戶端軟件的實現
項目結構如下:
主要的業務邏輯在這裡SplashActivity.java<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4KPHByZSBjbGFzcz0="brush:java;">
package com.xuliugen.mobilesafe;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import net.tsz.afinal.FinalHttp;
import net.tsz.afinal.http.AjaxCallBack;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.DialogInterface.OnCancelListener;
import android.content.DialogInterface.OnClickListener;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.animation.AlphaAnimation;
import android.widget.TextView;
import android.widget.Toast;
/**
* splash界面的作用
* 1、用來展現產品的Logo;
* 2、應用程序初始化的操作;
* 3、檢查應用程序的版本;
* 4、檢查當前應用程序是否合法注冊;
*
*
* 更新安裝的話要使用簽名
* @author xuliugen
*
*/
public class SplashActivity extends Activity {
protected static final int SHOW_UPDATE_DIALOG = 0;
protected static final int ENTER_HOME = 1;
protected static final int URL_ERROR = 2;
protected static final int NETWORK_ERROR = 3;
protected static final int JSON_ERROR = 40;
private TextView tv_splash_version;
private TextView tv_update_info;//升級進度
private String description;// 版本信息的描述
private String apkurl;// 版本更新的地址
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
tv_splash_version = (TextView) this.findViewById(R.id.tv_splash_version);
tv_update_info = (TextView) findViewById(R.id.tv_update_info);
tv_splash_version.setText(版本號: + getVersionName());
// 檢查更新
checkUpdate();
// 設置動畫
AlphaAnimation alphaAnimation = new AlphaAnimation(0.2f, 1.0f);
alphaAnimation.setDuration(3000);// 設置動畫的時長
//執行動畫
findViewById(R.id.rl_root_splash).startAnimation(alphaAnimation);
}
/**
* 由於更新界面是在主線程中操作
*
* 所以可以使用handler,當子線程中運行結束的時候們可以通知主線程進行相關的操作
*/
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//得到handler發送的message消息進行處理
switch (msg.what) {
case SHOW_UPDATE_DIALOG:// 顯示升級的對話框
showUpdateDialog();
break;
case ENTER_HOME:// 進入主頁面
enterHome();
break;
case URL_ERROR:// URL錯誤
enterHome();
Toast.makeText(getApplicationContext(), URL錯誤, 0).show();
break;
case NETWORK_ERROR:// 網絡異常
enterHome();
Toast.makeText(SplashActivity.this, 網絡異常, 0).show();
break;
case JSON_ERROR:// JSON解析出錯
enterHome();
Toast.makeText(SplashActivity.this, JSON解析出錯, 0).show();
break;
default:
break;
}
}
};
/**
* 檢查是否有新版本
*
* 需要請求網絡,一般在子線程中使用
*/
private void checkUpdate() {
new Thread() {
public void run() {
// URL:http://172.23.252.89:8080/updateinfo.json
Message message = Message.obtain();// 得到一個存在的信息,用於存放更新的信息
long startTime = System.currentTimeMillis();
try {
URL url = new URL(getString(R.string.serverurl));
//URL url = new URL(http://172.23.252.89:8080/updateinfo.json);
// 聯網操作
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setRequestMethod(GET);//設置請求方式
httpURLConnection.setConnectTimeout(4000);//設置超時時間
int code = httpURLConnection.getResponseCode();// 獲得響應碼
if (code == 200) {// 成功
InputStream inputStream = httpURLConnection.getInputStream();
//把流轉換為一個String類型
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
while((len = inputStream.read(buffer))!=-1){
baos.write(buffer, 0, len);
}
inputStream.close();
String result = baos.toString();//得到string類型的數據
baos.close();
//因為得到的數據是一個json的string所以要json解析
JSONObject jsonObj = new JSONObject(result);
//得到服務器的版本信息
String version = (String) jsonObj.get(version);
description = (String) jsonObj.get(description);
apkurl = (String) jsonObj.get(apkurl);
//校驗是否有新版本
if (getVersionName().equals(version)) {// 版本一致,進入主界面
message.what = ENTER_HOME;
} else {// 有新版本,彈出一個升級對話框
message.what = SHOW_UPDATE_DIALOG;
}
}
} catch (MalformedURLException e) {
message.what = URL_ERROR;
e.printStackTrace();
} catch (IOException e) {
message.what = NETWORK_ERROR;
e.printStackTrace();
} catch (JSONException e) {
message.what = JSON_ERROR;
e.printStackTrace();
} finally {
long endTime = System.currentTimeMillis();
long dTime = endTime-startTime;//花費的時間
//在界面中停留3秒
if(dTime < 3000){
try {
Thread.sleep(3000-dTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
handler.sendMessage(message);// 將消息發送出去
}
}
}.start();
}
/**
* 得到應用層序的版本名稱
*
* @return
*/
private String getVersionName() {
// 用於管理安裝的apk和未安裝的apk
PackageManager packageManager = getPackageManager();
try {
// 得到apk的功能清單文件:為了防止出錯直接使用getPackageName()方法獲得包名
// packageManager.getPackageInfo(com.xuliugen.mobilesafe, 0);
PackageInfo packageInfo = packageManager.getPackageInfo(getPackageName(), 0);
//返回版本名稱
return packageInfo.versionName;
} catch (NameNotFoundException e) {
e.printStackTrace();
return ;
}
}
/**
* 彈出升級對話框
*/
protected void showUpdateDialog() {
AlertDialog.Builder builder = new Builder(this);
builder.setTitle(提示升級);
// builder.setCancelable(false);//強制升級:就是不讓用戶取消
builder.setMessage(description);//為dialog設置信息
builder.setOnCancelListener(new OnCancelListener() { //
@Override
public void onCancel(DialogInterface dialog) {
// 進入主頁面
enterHome();
dialog.dismiss(); // 取消顯示對話框
}
});
builder.setNegativeButton(下次再說, new OnClickListener() {// 取消
@Override
public void onClick(DialogInterface dialog, int which) {
// 進入主頁面
enterHome();
dialog.dismiss(); // 取消顯示對話框
}
});
builder.setPositiveButton(立刻升級, new OnClickListener() {//確認
@Override
public void onClick(DialogInterface dialog, int which) {
// 下載APK,並且替換安裝
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {//得到sd卡的狀態
// sdcard存在
// 使用afnal下載apk文件
FinalHttp finalhttp = new FinalHttp();
// 得到sdcard路徑
String SDCARD_PATH = Environment
.getExternalStorageDirectory()
.getAbsolutePath()
+ /mobilesafe2.0.apk;
finalhttp.download(apkurl, SDCARD_PATH,
new AjaxCallBack
其中使用的把流轉化為一個String類型的方法可以封裝為一個工具類:
StreamTools.java
package com.xuliugen.mobilesafe.utils;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* 把流轉換為一個String類型
*
* @author xuliugen
*
*/
public class StreamTools {
/**
* @param is 輸入流
* @return String 返回的字符串
* @throws IOException
*/
public static String readFromStream(InputStream is) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
while ((len = is.read(buffer)) != -1) {
baos.write(buffer, 0, len);
}
is.close();
String result = baos.toString();
baos.close();
return result;
}
}
注意:我們的簽名一定要牢記,但是如果忘記也有方法解決:
(1)改簽名:這將無法覆蓋安裝,這是包名不變的情況,這就要求用戶先卸載以前的應用,體驗不佳!
(2)改包名:重新簽名,這就相當於手機安裝兩個應用,但是可以用技術卸載第一個應用。
Fragment是Android API中的一個類,它代表Activity中的一部分界面;你可以在一個Activity界面中使用多個Fragment,或者在多個Activ
最近在使用Android Studio 進行開發一款應用,涉及到新浪的登錄,但是新浪登錄的sdk需要引用so文件,用Studio找了半天沒找到合適的方法,不想
之前一旦時間覺得不知道看些什麼學些什麼還打游戲,有點頹廢。然後想想總得繼續學習,正好I/O大會剛結束,那就來看一些新東西https://github.com/ddwhan
微信是一個生活方式。為了更好的幫助你理解我們在打造綠色、健康的互聯網生態環境上做出的努力,我們對微信個人帳號限制登錄管理整理如下常見問題與解答:一、何種行為