继续
之前对比了用户和服务器端版本,当可升级的时候,要做进一步处理,而不仅仅是toast一个"有新版本"
case MSG_VERSION_DIFF:
//弹出通知
Builder builder = new Builder(SplashActivity.this);
builder.setTitle("发现新版本");
builder.setMessage(description);
//需要实现一个MyDialogOnclickListener传进来
builder.setPositiveButton("升级",new MyDialogOnclickListener());
builder.setNegativeButton("取消",new MyDialogOnclickListener());
builder.show();
break;
default:
break;
}
};
};
class MyDialogOnclickListener implements OnClickListener{
@Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
}
}
继续~对于点击事件,需要判断,确认就直接下载,取消就回去
确认:下载,这里用之前做的app,去info里改下信息,并将apk放到root里
涉及到文件的保存,这里用AsyncHttpClient,需要loopj,拷贝过来后,base里有问题,去掉原有导包重新来
class MyDialogOnclickListener implements OnClickListener{
@Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
if(which == DialogInterface.BUTTON_POSITIVE){
//用户点击了确认下载。这里开始去下载最新版本
AsyncHttpClient asyncHttpClient = new AsyncHttpClient();
//需要一个handler
asyncHttpClient.get(downloadurl, new MyDownloadHandler());
}else{
//用户点击了取消下载。这时候应该跳入到主界面
}
}
}
class MyDownloadHandler extends AsyncHttpResponseHandler{
@Override
public void onSuccess(int statusCode, Header[] headers,
byte[] responseBody) {
// TODO Auto-generated method stub
}
@Override
public void onFailure(int statusCode, Header[] headers,
byte[] responseBody, Throwable error) {
// TODO Auto-generated method stub
}
}
下载并安装:
@Override
public void onSuccess(int statusCode, Header[] headers,
byte[] responseBody) {
// TODO Auto-generated method stub
File file = new File("storage/sdcard/mobilesafe.apk");
try {
FileOutputStream fos = new FileOutputStream(file);
fos.write(responseBody);
fos.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
installapk(file);
}
private void installapk(File file) {
// TODO Auto-generated method stub
Intent intent = new Intent("android.intent.action.VIEW");
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
startActivity(intent);
}
此时走起一个发现解析错误,需要写权限
OK~能够安装
但是这个还有一个方法需要添加,显示安装进度,需要一个view,在splash的layout里加入
<TextView
android:id="@+id/tv_splash_downloadprogress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_alignParentBottom="true"
android:textColor="#000000" />
oncreate里初始化
@Override
public void onProgress(int bytesWritten, int totalSize) {
// TODO Auto-generated method stub
super.onProgress(bytesWritten, totalSize);
tv_splash_downloadprogress.setText(bytesWritten+"/"+totalSize);
}
bin目录下的apk没有签名,不能发布到市场上,小范围安装可以
关于签名,导出整个项目时,
没有签名,系统有一个测试签名,在windows下的preference的build里有一个路径
这个可以填到location里,但是还需要一个password,一般就是android
自己创建的可以和系统的类似,改一下最后的文件名就好,第二次填密码那要注意填有效期,必须能达到2033年
发布不同版本时,首选是包名必须相同,其次是签名一致,所以在升级时要用到之前的签名,当然manifest里的版本号也要改下~
继续,当可以升级,用户点击取消则应该跳到homeactivity,要完成这个activity和layout
else{
//用户点击了取消下载。这时候应该跳入到主界面
enterHome();
}
}
}
private void enterHome() {
Intent intent = new Intent(SplashActivity.this, HomeActivity.class);
startActivity(intent);
}
homeactivity
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
public class HomeActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
TextView tv = new TextView(this);
tv.setText("我是主界面");
setContentView(tv);
}
}
manifest里要声明下
注意handler里,版本相同时,进入home
当出现意外时,比如服务器挂了,这个时候应该有相应处理,这时不能在异常处理里用enterhome(),因为主线程不能操作UI,所以应该利用handler发消息
注意,由于这里涉及多种消息的发送,其实可以做一些优化,把msg的声明拿出来,添加一个finally,在里面发消息,而各种状况里只需说明是哪种消息即可
异常里的消息
并且提示错误代码,给出反馈
有一个细节,当初设了一个notitle,但是背景成了黑色,现在要调成白色并且依然notitle,那么可以在values里的style加一个notitle条目,再在manifest里改主题
取消后,带参数的跳转
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// TODO Auto-generated method stub
super.onActivityResult(requestCode, resultCode, data);
if (requestCode==100 && resultCode==RESULT_CANCELED) {
enterHome();
}
}
这里有两个取消,一个是直接不升级,进入home,另一个是点了升级,但是在安装的时候又选择不安张,此时也应该可以跳转到home
在安装里应该是一个带参数的跳转
要实现进入下载或者homeactivity后点back键返回九宫格,则需要销毁这个activity,这样就能回到栈底
注意IP地址改动,服务器端的info文件里的地址也要改动。。
在超时等待的时候,加一个小圆圈转动,提升体验~需要ProgressBar
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/tv_splash_version"
android:layout_marginTop="5dp"
android:layout_centerHorizontal="true"/>
</RelativeLayout>
这一段的完整代码
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import org.apache.http.Header;
import org.json.JSONException;
import org.json.JSONObject;
import com.loopj.android.http.AsyncHttpClient;
import com.loopj.android.http.AsyncHttpResponseHandler;
import utils.WebUtils;
import android.app.Activity;
import android.app.AlertDialog.Builder;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.widget.TextView;
import android.widget.Toast;
public class SplashActivity extends Activity {
protected static final int MSG_VERSION_SAME =0;
protected static final int MSG_VERSION_DIFF =1;
protected static final int MSG_ERROR_URLMALFORMED = 10;
protected static final int MSG_ERROR_JSON = 20;
protected static final int MSG_ERROR_IO = 30;
private String description;
private String downloadurl;
private String version;
private TextView tv_splash_downloadprogress;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
TextView tv_splash_version = (TextView) findViewById(R.id.tv_splash_version);
//上面的声明要注意是空字符串,而不是null
tv_splash_version.setText("版本: "+getVersion());
//解析下载进度
tv_splash_downloadprogress = (TextView) findViewById(R.id.tv_splash_downloadprogress);
//获取服务器端版本号
Update();
}
Handler myHandler = new Handler(){
public void handleMessage(android.os.Message msg){
switch(msg.what){
case MSG_VERSION_SAME:
//进入主界面
enterHome();
break;
case MSG_VERSION_DIFF:
//弹出通知
Builder builder = new Builder(SplashActivity.this);
builder.setTitle("发现新版本");
builder.setMessage(description);
//需要实现一个MyDialogOnclickListener传进来
builder.setPositiveButton("升级",new MyDialogOnclickListener());
builder.setNegativeButton("取消",new MyDialogOnclickListener());
builder.show();
break;
case MSG_ERROR_IO:
Toast.makeText(getApplicationContext(), "错误代码"+MSG_ERROR_IO, 1).show();
enterHome();
break;
case MSG_ERROR_JSON:
Toast.makeText(getApplicationContext(), "错误代码"+MSG_ERROR_JSON, 1).show();
enterHome();
break;
case MSG_ERROR_URLMALFORMED:
Toast.makeText(getApplicationContext(), "错误代码"+MSG_ERROR_URLMALFORMED, 1).show();
enterHome();
break;
default:
break;
}
};
};
class MyDialogOnclickListener implements OnClickListener{
@Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
if(which == DialogInterface.BUTTON_POSITIVE){
//用户点击了确认下载。这里开始去下载最新版本
AsyncHttpClient asyncHttpClient = new AsyncHttpClient();
//需要一个handler
asyncHttpClient.get(downloadurl, new MyDownloadHandler());
}else{
//用户点击了取消下载。这时候应该跳入到主界面
enterHome();
}
}
}
private void enterHome() {
Intent intent = new Intent(SplashActivity.this, HomeActivity.class);
startActivity(intent);
//要实现点back键返回开始的activity,则需要销毁这个activity,这样就能回到栈底
finish();
}
//进入安装后用户又取消,这时候应该能直接进入home,这是带参数值的跳转
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// TODO Auto-generated method stub
super.onActivityResult(requestCode, resultCode, data);
if (requestCode==100 && resultCode==RESULT_CANCELED) {
enterHome();
}
}
class MyDownloadHandler extends AsyncHttpResponseHandler{
@Override
public void onSuccess(int statusCode, Header[] headers,
byte[] responseBody) {
// TODO Auto-generated method stub
File file = new File("storage/sdcard/mobilesafe.apk");
try {
FileOutputStream fos = new FileOutputStream(file);
fos.write(responseBody);
fos.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
installapk(file);
}
private void installapk(File file) {
// TODO Auto-generated method stub
Intent intent = new Intent("android.intent.action.VIEW");
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
startActivityForResult(intent,100);
}
@Override
public void onProgress(int bytesWritten, int totalSize) {
// TODO Auto-generated method stub
super.onProgress(bytesWritten, totalSize);
tv_splash_downloadprogress.setText(bytesWritten+"/"+totalSize);
}
@Override
public void onFailure(int statusCode, Header[] headers,
byte[] responseBody, Throwable error) {
// TODO Auto-generated method stub
}
}
private void Update() {
// TODO Auto-generated method stub
new Thread(new Runnable(){
@Override
public void run() {
String path = "http://192.168.3.100/version_info.json";
Message msg = myHandler.obtainMessage();
try {
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(5000);
conn.setConnectTimeout(2000); //实际发布版本的时候,超时实际最好稍微长一些
conn.setRequestMethod("GET");
conn.connect();
if (conn.getResponseCode()==200) {
InputStream is= conn.getInputStream();
String jsontext = WebUtils.gettextFromInputStream(is, null);
JSONObject jsonObject = new JSONObject(jsontext);
version = jsonObject.getString("version");
description = jsonObject.getString("description");
downloadurl = jsonObject.getString("downloadurl");
System.out
.println("SplashActivity.Update().new Runnable() {...}.run()"
+version
+description
+downloadurl);
if(version.equals(getVersion())){
//版本一致则进入主页
msg.what = MSG_VERSION_SAME;
}else{
//不一致则弹出dialog告诉用户,此时需要handler来处理
msg.what = MSG_VERSION_DIFF;
}
}
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
msg.what = MSG_ERROR_URLMALFORMED;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
msg.what = MSG_ERROR_IO;
}catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
msg.what = MSG_ERROR_JSON;
}finally{
myHandler.sendMessage(msg);
}
}
}).start();
}
private String getVersion() {
//获取版本号
PackageManager pm = getPackageManager();
PackageInfo packageinfo;
String version="";
try {
//第一个参数应该为manifest里的包名而不是工程里的包名,后直接以方法获取~
packageinfo = pm.getPackageInfo(getPackageName(), 0);
version = packageinfo.versionName;
} catch (NameNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return version;
}
}