作为一个开发的小白,在学习课程以及网上各种找资料实现自动更新,在此记录一下(:з」∠)。
- 在主页面显示更新进度
- 在通知栏显示更新进度
1.打开APP立即检查更新,在主页面显示更新进度。
在进入Mainactivity时检查APP版本号和后台版本号是否匹配,不匹配则弹出对话框。
具体为下:
在子线程进行获取后台APP的版本号以及更新信息的操作,后台的大佬传的xml文件:
public class UpdateApkThread extends Thread {
private Context context;
private Handler handler;
public UpdateApkThread(Context context, Handler handler) {
super();
this.context = context;
this.handler = handler;
}
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
try {
URL url = new URL(Bean.UPDATE_APK);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000);
InputStream is = conn.getInputStream();
if (200 == conn.getResponseCode()) {
String versionCode = "";
String download= "";
String content = "";
XmlPullParser parser = Xml.newPullParser();
parser.setInput(is, "utf-8");
int type = parser.getEventType();
Map<String, String> map = new HashMap<String, String>();
while(type != XmlPullParser.END_DOCUMENT){
switch (type) {
case XmlPullParser.START_TAG:
if("versioncode".equals(parser.getName())){
versionCode = parser.nextText(); //获取版本号
} else if ("download".equals(parser.getName())) {
download = parser.nextText(); //获取下载地址
map.put("download", download);
} else if ("content".equals(parser.getName())) {
content = parser.nextText();
map.put("content", content);
}
break;
}
type = parser.next();
}
Log.e("xml文件", versionCode + " " + download);
if (Integer.valueOf(versionCode) > getVersionCode()) {
Log.i("", "版本号不同,提示用户升级 ");
Message msg = new Message();
msg.what = Bean.UPDATE_SUCCESS;
msg.obj = map;
handler.sendMessage(msg);
} else {
Log.i("", "版本号相同无需升级");
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取当前程序的版本号
* @return
* @throws NameNotFoundException
*/
private int getVersionCode() throws NameNotFoundException {
// 获得已安装的应用程序信息 。可以通过getPackageManager()方法获得
PackageManager packageManager = context.getPackageManager();
//getPackageName()是当前类的包名,0代表是获取版本信息
PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(), 0);
return packageInfo.versionCode;
}
}
Mainactivity中获取子线程中服务器传来的APP下载地址以及更新信息。
private Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case Bean.UPDATE_SUCCESS:
Map<String, String> map = (Map<String, String>) msg.obj;
url = map.get("download");
message = map.get("message");
showUpdateDialog();
Log.e("更新地址和更新内容", url + message);
break;
default:
break;
}
};
};
new UpdateApkThread(MainActivity.this, handler).start();
protected void showUpdateDialog() {
// TODO Auto-generated method stub
CustomDialog.Builder builer = new CustomDialog.Builder(this) ;
builer.setTitle("版本升级");
//当点确定按钮时从服务器上下载 新的apk然后安装
builer.setMessage(message);
builer.setPositiveButton("确定", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
Log.i("", "下载apk,更新");
downLoadApk();
}
});
builer.setNegativeButton("取消", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
dialog.dismiss();
}
});
builer.create().show();
}
/*
* 从服务器中下载APK
*/
protected void downLoadApk() {
final ProgressDialog pd; //进度条对话框
pd = new ProgressDialog(this);
pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
pd.setMessage("正在下载更新");
pd.show();
new Thread(){
@Override
public void run() {
try {
File file = DownloadApk.getFileFromServer(url, pd);
sleep(3000);
installApk(file);
pd.dismiss();
} catch (Exception e) {
Message msg = new Message();
msg.what = 0;
handler.sendMessage(msg);
e.printStackTrace();
}
}}.start();
}
//安装apk
protected void installApk(File file) {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
//执行的数据类型
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
startActivity(intent);
}
public class DownloadApk {
public static File getFileFromServer(String path, ProgressDialog pd) throws Exception{
//如果相等的话表示当前的sdcard挂载在手机上并且是可用的
if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000);
//获取到文件的大小
pd.setMax(conn.getContentLength());
InputStream is = conn.getInputStream();
String filePath = Environment.getExternalStorageDirectory() + "/***/*****.apk";
checkLocalPath(filePath);
File file = new File(filePath);
FileOutputStream fos = new FileOutputStream(file);
BufferedInputStream bis = new BufferedInputStream(is);
byte[] buffer = new byte[1024];
int len ;
int progress = 0;
while((len = bis.read(buffer)) != -1){
fos.write(buffer, 0, len);
progress += len;
//获取当前下载量
pd.setProgress(progress);
}
fos.close();
bis.close();
is.close();
return file;
}
else{
return null;
}
}
private void checkLocalPath(String localFilePath) {
// TODO Auto-generated method stub
File dir = new File(localFilePath.substring(0, localFilePath.lastIndexOf("/")));
Log.e("", ""+localFilePath.substring(0, localFilePath.lastIndexOf("/")));
if (! dir.exists()) {
dir.mkdir();
if (dir.mkdir()) {
Log.e("目录", "创建目录成功");
}
}
File file = new File(localFilePath);
if (! file.exists()) {
try {
file.createNewFile();
if (file.createNewFile()) {
Log.e("apk文件", "创建文件成功");
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
在网上学习的更新,在主页显示缺点是用户在进行更新时不能进行其他操作,所以最好在通知栏显示更新进度。
2.打开APP立即检查更新,在通知栏显示更新进度。在慕课网学习的使用了线程池等,代码有点多,我没有使用线程池,仅结合其它简化了一下,有优化的部分期待指正。
获取后台APP的版本号以及更新信息的操作同上。
在对话框确定时启动服务:
protected void showUpdateDialog() {
// TODO Auto-generated method stub
CustomDialog.Builder builer = new CustomDialog.Builder(this) ;
builer.setTitle("版本升级");
//当点确定按钮时从服务器上下载 新的apk然后安装
builer.setMessage(message);
builer.setPositiveButton("确定", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
Log.i("", "下载apk,更新");
Intent intentDownload = new Intent(MainActivity.this, DownloadService.class);
intentDownload.putExtra("apkUrl", url);
startService(intentDownload);
dialog.dismiss();
}
});
builer.setNegativeButton("取消", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
dialog.dismiss();
}
});
builer.create().show();
}
启动服务,在服务中设置通知栏(下载中的通知栏时自定义的就不贴布局了),建立子线程进行进度的接收,更新通知。
public class DownloadService extends Service {
private NotificationManager manager;
private Notification notification;
private String apkUrl;
private String filePath;
private int progress;
private RemoteViews view;
private Handler handler = new Handler(){
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case 888:
createNotification("下载完成", progress);
stopSelf();
break;
default:
stopSelf();
break;
}
};
};
@Override
public void onCreate() {
// TODO Auto-generated method stub
manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
filePath = Environment.getExternalStorageDirectory() + "/***/*****.apk";
checkLocalPath(filePath);
super.onCreate();
}
private void checkLocalPath(String localFilePath) {
// TODO Auto-generated method stub
File dir = new File(localFilePath.substring(0, localFilePath.lastIndexOf("/")));
Log.e("", ""+localFilePath.substring(0, localFilePath.lastIndexOf("/")));
if (! dir.exists()) {
dir.mkdir();
if (dir.mkdir()) {
Log.e("目录", "创建目录成功");
}
}
File file = new File(localFilePath);
if (! file.exists()) {
try {
file.createNewFile();
if (file.createNewFile()) {
Log.e("apk文件", "创建文件成功");
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
if (intent == null) {
createNotification("下载失败", 0);
stopSelf();
}
apkUrl = intent.getStringExtra("apkUrl");
createNotification("开始下载", 0);
startDownload();
return super.onStartCommand(intent, flags, startId);
}
private void startDownload() {
// TODO Auto-generated method stub
new DownloadApkThread().start();
}
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
private void createNotification(String result, int progress) {
NotificationCompat.Builder build = new NotificationCompat.Builder(this);
build.setSmallIcon(R.drawable.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher))
.setContentTitle(getString(R.string.app_name))
.setContentText(result);
build.setAutoCancel(false);
build.setWhen(System.currentTimeMillis());
build.setTicker(result);
build.setContentIntent(progress >= 100 ? getContentIntent() : PendingIntent.getActivity(this, 0, new Intent(), PendingIntent.FLAG_UPDATE_CURRENT));
notification = build.build();
if (progress < 100) {
//自定义notification
view = new RemoteViews(getPackageName(), R.layout.notification_update);
view.setTextViewText(R.id.noti_title, getString(R.string.app_name) + result);
view.setTextViewText(R.id.noti_percent, "0%");
view.setProgressBar(R.id.noti_progress, 100, 0, false);
notification.contentView = view;
}
manager.notify(R.layout.notification_update, notification);
}
public PendingIntent getContentIntent() {
File apkFile = new File(filePath);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setDataAndType(Uri.parse("file://" + apkFile.getAbsolutePath()), "application/vnd.android.package-archive");
return PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
class DownloadApkThread extends Thread {
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
int totalSize;// 文件总大小
int downloadCount = 0;// 已经下载好的大小
int limit = 0; //限制一下notification的更新频率
//如果相等的话表示当前的sdcard挂载在手机上并且是可用的
if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
URL url = null;
FileOutputStream fos = null;
BufferedInputStream bis = null;
try {
url = new URL(apkUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000);
//获取到文件的大小
totalSize = conn.getContentLength();
fos = new FileOutputStream(filePath);
bis = new BufferedInputStream(conn.getInputStream());
byte[] buffer = new byte[1024];
int len = -1;
while((len = bis.read(buffer)) != -1){
fos.write(buffer, 0, len);
downloadCount += len;
Message msg = new Message();
if (downloadCount <= totalSize) {
progress = (int) (downloadCount * 100 / totalSize);
if (limit % 30 == 0 && progress < 100) {
//createNotification("正在下载", progress);
Log.e("Aa", progress+"");
view.setTextViewText(R.id.noti_percent, progress + "%");
view.setTextViewText(R.id.noti_title, getString(R.string.app_name) + "正在下载");
view.setProgressBar(R.id.noti_progress, 100, progress, false);
notification.contentView = view;
manager.notify(R.layout.notification_update, notification);
}
if (progress >= 100) {
msg.what = 888;
handler.sendMessage(msg);
}
}
limit++;
}
} catch (MalformedURLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
fos.close();
bis.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
}
注意:Android6.0由于对手机安全的优化,需要动态申请读写权限
// Android 6.0 后需要动态申请读写权限
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {
"android.permission.READ_EXTERNAL_STORAGE",
"android.permission.WRITE_EXTERNAL_STORAGE"};
public static void verifyStoragePermissions(Activity activity) {
try {
//检测是否有写的权限
int permission = ActivityCompat.checkSelfPermission(activity,
"android.permission.WRITE_EXTERNAL_STORAGE");
if (permission != PackageManager.PERMISSION_GRANTED) {
// 没有写的权限,去申请写的权限,会弹出对话框
ActivityCompat.requestPermissions(activity, PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE);
}
} catch (Exception e) {
e.printStackTrace();
}
}
学习的大概就是以上,记录记录。