安卓版本更新
1.在应用首界面onCreate中调用initVersion();
/**
* 更新版本
*/
private
void
initVersion() {
//
TODO
Auto-generated method stub
// 获取版本号
getLocalVersion();
String url = Urls.
VERSION_CODE
;
Log.
i
("更新版本url---"
, url);
Request<String> request = NoHttp.
createStringRequest
(url,
RequestMethod.
POST
);
queue
.add(222, request,
new
OnResponseListener<String>() {
@Override
public
void
onStart(
int
what) {
//
TODO
Auto-generated method stub
}
@Override
public
void
onSucceed(
int
what, Response<String> response) {
//
TODO
Auto-generated method stub
Log.
i
("onSucceed---"
, response.get());
Gson gson =
new
Gson();
VersionUpdate update = gson.fromJson(response.get(),
VersionUpdate.
class
);
String apkUrl = update.appmanage
.appUrl
;
// 最新
apk
下载地址
String newversion_code = update.appmanage
.version_code
;
int
new_version_code = Integer.
parseInt
(newversion_code);
String errorCodes = update.errorCode
;
Log.
i
("appUrl---"
, apkUrl);
Log.
i
("version_code---"
, newversion_code);
Log.
i
("errorCode2---"
, errorCodes);
if
("0"
.equals(errorCodes)) {
// 0 没有获取到后台版本号
}
else
if
("1"
.equals(errorCodes)) {
// 1 获取到后台版本号
if
(new_version_code == localCode
) {
// 相同 说明当前已经是最新版本
return
;
}
else
{
// 说明有新版本需要更新
// 弹对话框提示用户去下载新版本
showUpdateDialog(apkUrl);
}
}
}
@Override
public
void
onFailed(
int
what, String url, Object tag,
Exception exception,
int
responseCode,
long
networkMillis) {
//
TODO
Auto-generated method stub
}
@Override
public
void
onFinish(
int
what) {
//
TODO
Auto-generated method stub
}
});
}
2.
获取应用当前版本号
private
int localCode;
/**
* 获取应用当前版本号
*/
private
void getLocalVersion() {
// 如何拿到版本信息?
pm = context.getPackageManager();
// 获取到对应的包下面的信息
// 写0获取到所有的 其他的代表写谁获取谁
try {
// PackageInfo 是对整个清单文件的封装
PackageInfo packageInfo = pm.getPackageInfo(context.getPackageName(), 0);
// ApplicationInfo 是Application节点的封装
localCode = packageInfo.versionCode;
//这里只获取localCode进行判断
}
catch (PackageManager.NameNotFoundException e){
//
TODO
Auto-generated catch block
e.printStackTrace();
}
}
3.
下载新版本
private
AlertDialog alertDialog
;
/**
* 下载新版本
*
*
@param
info
*
@param
apkUrl
*/
private
void
showUpdateDialog
(
final
String apkUrl) {
// 普通对对话框
final
AlertDialog.Builder builder =
new
AlertDialog.Builder(context
);
alertDialog
= builder.create();
LayoutInflater inflater = ((Activity) context
).getLayoutInflater();
final
View layout = inflater.inflate(R.layout.
dialogversion
,
null
);
// TextView tv_info = (TextView)
// layout.findViewById(R.id.tv_dialoge_info);
Butt
on bt_cancle = (Button) layout.findViewById(R.id.
bt_cancle_dialog
);
Button bt_sure = (Button) layout.findViewById(R.id.
bt_sure_dialog
);
// tv_info.setText(info);
alertDialog
.setView(layout);
alertDialog
.setIcon(R.drawable.
zc
);
// 设置ProgressDialog 是否可以按退回按键取消
alertDialog
.setCancelable(
false
);
// 如果不想让对话框关闭
// builder.setCancelable(false);
// 给对话框设置一个消失的监听
alertDialog
.setOnCancelListener(
new
DialogInterface.OnCancelListener() {
@Override
public
void
onCancel(DialogInterface dialog) {
}
});
bt_cancle.setOnClickListener(
new
View.OnClickListener() {
@Override
public
void
onClick(View view) {
//
TODO
点击的是(暂不更新)
alertDialog
.dismiss();
}
});
bt_sure.setOnClickListener(
new
View.OnClickListener() {
@Override
public
void
onClick(View view) {
//
TODO
点击的是(立即更新)
alertDialog
.dismiss();
//android6.0以后动态申请读写权限
int permission_write=ContextCompat.checkSelfPermission(MainActivity.this,
Manifest.permission.WRITE_EXTERNAL_STORAGE);
int permission_read=ContextCompat.checkSelfPermission(MainActivity.this,
Manifest.permission.READ_EXTERNAL_STORAGE);
if(permission_write!= PackageManager.PERMISSION_GRANTED
|| permission_read!=PackageManager.PERMISSION_GRANTED){
Toast.makeText(mContext, "正在请求权限", Toast.LENGTH_SHORT).show();
//申请权限,特征码自定义为1,可在回调时进行相关判断
ActivityCompat.requestPermissions(MainActivity.this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE},1);
}else{
downloadApk(apkUrlstr);
}
}
});
alertDialog
.show();
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode){
case 1:
if(grantResults.length>0 && grantResults[0]==PackageManager.PERMISSION_GRANTED){
//权限已成功申请
MyLog.i("权限已成功申请=============",apkUrlstr);
downloadApk(apkUrlstr);
}else{
//用户拒绝授权
Toast.makeText(this, "无法获取SD卡读写权限", Toast.LENGTH_SHORT).show();
finish();
}
break;
default:
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
3.1 dialogversion布局
<?
xml
version=
"1.0"
encoding=
"utf-8"?>
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_marginLeft=
"50dp"
android:layout_marginRight=
"50dp"
android:background=
"@drawable/shape_dialoge"
android:orientation=
"vertical">
<
TextView
android:id=
"@+id/tv_dialoge_title"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_margin=
"10dp"
android:text
=
"检测到新版本"
android:textColor=
"@color/black"
android:gravity=
"center"
android:textSize
=
"20dp"
/>
<
ImageView
android:layout_width=
"match_parent"
android:layout_height=
"1dp"
android:background=
"#3EB3F9"
/>
<!-- <TextView
android:id="@+id/tv_content_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:text="更新内容:"
android:textColor="@color/black"
android:textSize="18dp" />
<TextView
android:id="@+id/tv_dialoge_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:text="XXXXXXXXXXXXXX
"
android:textColor="@color/black"
android:textSize="16dp" /> -->
<
ImageView
android:layout_width=
"match_parent"
android:layout_height=
"1dp"
android:background=
"#3EB3F9"
/>
<
LinearLayout
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:orientation=
"horizontal">
<
Button
android:id=
"@+id/bt_cancle_dialog"
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
android:layout_weight=
"100"
android:background=
"#fff"
android:text
=
"暂不更新"
android:textColor=
"#919191"
android:textSize
=
"20dp"
/>
<
ImageView
android:layout_width=
"0dp"
android:layout_height=
"match_parent"
android:layout_weight=
"1"
android:background=
"#3EB3F9"
/>
<
Button
android:id=
"@+id/bt_sure_dialog"
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
android:layout_weight=
"100"
android:background=
"#fff"
android:text
=
"立即更新"
android:textColor=
"#3EB3F9"
android:textSize
=
"20dp"
/>
</
LinearLayout>
</
LinearLayout>
3.2 zc样式
<?
xml version=
"1.0" encoding=
"utf-8"?>
<
layer-list xmlns:android=
"
http://schemas.android.com/apk/res/android"
;>
<
item>
<
shape>
<
solid android:color=
"#dddddd" />
</
shape>
</
item>
<
item
android:left=
"1dp"
android:right=
"1dp"
android:top=
"1dp"
android:bottom=
"1dp">
<
shape>
<
solid android:color=
"#f4f4f4"/>
</
shape>
</
item>
</
layer-list>
4.下载appk过程
private AlertDialog pd;
private
void downloadApk(String apkurl) {
// 下载维护的线程池数
DownloadQueue downloadQueue = NoHttp.
newDownloadQueue();
Log.
i("sdcard--", MyResource.
DOWNLOAD_PATH);
// 下载请求
DownloadRequest downloadRequest = NoHttp.
createDownloadRequest(apkurl,
RequestMethod.
GET, MyResource.
DOWNLOAD_PATH,
"example.apk",
true,
true);
// 下载请求添加在下载队列里
downloadQueue.add(3, downloadRequest,
new DownloadListener() {
private ProgressBar pb_progress;
private TextView tv_max;
private TextView tv_progress;
public
long allCount;
@Override
public
void onDownloadError(
int what, Exception exception) {
Toast.
makeText(context, "服务器忙,下载失败", Toast.
LENGTH_SHORT).show();
Toast.
makeText(context, exception.getMessage(),
Toast.
LENGTH_SHORT).show();
// 对话框消失掉
if (pd !=
null) {
pd.dismiss();
}
}
@Override
public
void onStart(
int what,
boolean isResume,
long rangeSize,
Headers responseHeaders,
long allCount) {
this.allCount = allCount;
final AlertDialog.Builder builder =
new AlertDialog.Builder(
context);
pd = builder.create();
LayoutInflater inflater = ((Activity) context)
.getLayoutInflater();
final View layout = inflater.inflate(R.layout.
dialog_download,
null);
tv_progress = (TextView) layout.findViewById(R.id.
tv_progress);
tv_max = (TextView) layout.findViewById(R.id.
tv_max);
pb_progress = (ProgressBar)
layout
.findViewById(R.id.
pb_progress);
pd.setView(layout);
DecimalFormat df =
new DecimalFormat("##.##");
tv_max.setText(df.format((allCount / 1024.00 / 1024.00)) + "M");
pd.setCancelable(
false);
pb_progress.setMax(100);
pd.show();
}
@Override
public
void onProgress(
int what,
int progress,
long fileCount) {
//正在下载
// 更新进度条
pb_progress.setProgress(progress);
DecimalFormat df =
new DecimalFormat("##.##");
tv_progress.setText(df.format((
double) progress
* (allCount / 1024.00 / 1024.00 / 100.00))
+ "M");
}
@Override
public
void onFinish(
int what, String filePath) {
// 下载完成
// 对话框消失掉
if (pd !=
null) {
pd.dismiss();
}
ToastUtils.
toast(context, "下载成功");
//先获取是否有安装未知来源应用的权限
checkInstall();
}
@Override
public
void onCancel(
int what) {
//
TODO
Auto-generated method stub
// 对话框消失掉
if (pd !=
null) {
pd.dismiss();
}
}
});
}
4.1 MyResource工具类
/**
* 用来存放一些公用的资源 比如 下载的路径
*
@author
Administrator
*
*/
public
class MyResource {
// 我们将跟我们软件相关的所有的文件放在
sd
卡的同一个路径下
//apk名字
private
static
final String
ROOT = "example";
// /
mnt
/
sdcard
/example
public
static
final String
ROOT_PATH = Environment.
getExternalStorageDirectory().getAbsolutePath()+"/"+
ROOT;
// 这个目录只跟下载的东西相关
// /
mnt
/
sdcard
/example/download
public
static
final String
DOWNLOAD_PATH =
ROOT_PATH+"/download";
}
4.2
dialog_download布局
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
<
LinearLayout
xmlns:android
=
"
http://schemas.android.com/apk/res/android"
;
android:layout_width
=
"match_parent"
android:layout_height
=
"wrap_content"
android:background
=
"#fff"
android:orientation
=
"vertical"
>
<
TextView
android:id
=
"@+id/tv_dialoge_title"
android:layout_width
=
"match_parent"
android:layout_height
=
"wrap_content"
android:layout_margin
=
"10dp"
android:text
=
"下载中。。。"
android:gravity
=
"center"
android:textSize
=
"20dp"
/>
<
ImageView
android:layout_width
=
"match_parent"
android:layout_height
=
"@dimen/x1"
android:background
=
"#20abff"
/>
<
ProgressBar
android:id
=
"@+id/pb_progress"
style
=
"?android:attr/progressBarStyleHorizontal"
android:layout_width
=
"match_parent"
android:layout_height
=
"20dp"
android:progressDrawable="@drawable/progressbar_background"
android:layout_marginBottom
=
"5dp"
android:layout_marginRight
=
"20dp"
android:layout_marginLeft
=
"20dp"
android:layout_marginTop
=
"20dp"
/>
<
LinearLayout
android:layout_marginBottom
=
"10dp"
android:layout_width
=
"match_parent"
android:layout_height
=
"wrap_content"
android:gravity
=
"right"
android:orientation
=
"horizontal"
>
<
LinearLayout
android:layout_marginRight
=
"40dp"
android:orientation
=
"horizontal"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
>
<
TextView
android:id
=
"@+id/tv_progress"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:text
=
"3M"
android:textSize
=
"16dp"
/>
<
TextView
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:text
=
" / "
android:textSize
=
"16dp"
/>
<
TextView
android:id
=
"@+id/tv_max"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:text
=
"5M"
android:textSize
=
"16dp"
/>
</
LinearLayout
>
</
LinearLayout
>
</
LinearLayout
>
4.3
@drawable/progressbar_background 布局
<?
xml version=
"1.0" encoding=
"utf-8"?>
<
layer-list xmlns:android=
"
http://schemas.android.com/apk/res/android"
; >
<
item android:id=
"@android:id/background">
<
shape>
<
corners android:radius=
"5dp" />
<
solid android:color=
"#A5D1DB" /> //这个颜色是pro
gressbar的背景颜色
</
shape>
</
item>
<
item android:id=
"@android:id/progress">
<
clip>
<
shape>
<
corners android:radius=
"5dp" />
<
solid android:color=
"#1E90FF" /> //这个颜色是progressbar的进度颜色
</
shape>
</
clip>
</
item>
</
layer-list>
4.4checkInstall (先获取是否有安装未知来源应用的权限)
private void checkInstall() {
boolean haveInstallPermission;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
//先获取是否有安装未知来源应用的权限
haveInstallPermission = getPackageManager().canRequestPackageInstalls();
if (!haveInstallPermission) {//没有权限
AlertDialog alertDialog = new AlertDialog.Builder(this)
.setTitle("请开启未知来源权限")
.setMessage("应用需要打开安装未知来源应用权限,请去设置中开启权限")
.setCancelable(false)
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
ToastUtil.showToast(MainActivity.this,"您拒绝了权限,应用无法正常使用!");
finish();
}
})
.setPositiveButton("去设置", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
toInStallPermissionSettingActivity();
}
}).create();
alertDialog.show();
return;
}
}
//有权限,进行安装操作
installAPK();
}
protected static final int REQUEST_CODE_INSTALL_PERMISSION = 2;
private void toInStallPermissionSettingActivity() {
Uri packageURI = Uri.parse("package:" + getPackageName());
//注意这个是8.0新API
Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, packageURI);
startActivityForResult(intent, REQUEST_CODE_INSTALL_PERMISSION);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(resultCode == RESULT_OK && requestCode == REQUEST_CODE_INSTALL_PERMISSION){
checkInstall();//以防万一,再次检查权限
}
}
4.5.自动安装app
private void installAPK() {
String fileName = MyResource.DOWNLOAD_PATH
+ "/example.apk";
try {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Uri uri;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
//7.0 Android N
//com.xxx.xxx.fileprovider为上述manifest中provider所配置相同
MyLog.i("大于7.0","11111111111111111");
uri = FileProvider.getUriForFile(mContext, "zz.bole.songjisn.fileprovider", new File(fileName));
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);//7.0以后,系统要求授予临时uri读取权限,安装完毕以后,系统会自动收回权限,该过程没有用户交互
} else {//7.0以下
MyLog.i("7.0以下","7.0以下");
uri = Uri.fromFile(new File(fileName));
}
intent.setDataAndType(uri, "application/vnd.android.package-archive");
// 查询所有符合 intent 跳转目标应用类型的应用,注意此方法必须放置在 setDataAndType 方法之后
List<ResolveInfo> resolveLists = mContext.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
// 然后全部授权
for (ResolveInfo resolveInfo : resolveLists){
String packageName = resolveInfo.activityInfo.packageName;
mContext.grantUriPermission(packageName, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
}
startActivity(intent);
} catch (IllegalArgumentException e) {
e.printStackTrace();
}catch (ActivityNotFoundException e){
e.printStackTrace();
}catch (Exception e){
e.printStackTrace();
}
}
4.6清单文件中加provider
<provider
android:authorities="你的包名.fileprovider"
android:name="android.support.v4.content.FileProvider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths"/>
</provider>
4.7@xml/filepaths res目录下新建xml目录
<?xml version="1.0" encoding="utf-8"?>
<resources>
<paths>
<external-path path="" name="download"/>
</paths>
</resources>