您的位置:首页 > 移动开发

Android app实现自更新和安装,权限检测适配Android6.0以下和Android6.0和Android7.0和Android8.0总结篇

2018-03-21 09:27 489 查看
首先下载问文件需要在AndroidManifest.xml里添加SD卡读写权限,下面两个权限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />下载app还需要一个下载帮助类,文件的读写流类;此类外界调用时需要传人Handler,主要负责app下载完成时通知外界做安装操作,此外还添加了安卓的系统通知栏Notification,负责在系统通知栏上显示下在进度,由于Android对通知栏做了重构,Notification只能安卓16以上的api调用,16以下用NotificationCompat,如果下兼容api16以下自行查阅NotificationCompat使用添加兼容,此外Android8.0对Notification的调用还与8.0以下的不一样!(如下看代码!)如果有同学不需要系统通知栏显示进度可自行屏蔽Notification的代码。也可以删了Notification的代码自己写一个Dialog进度条去显示进度!

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.os.Build;
import android.os.Environment;
import android.os.Handler;
import android.util.Log;
import com.qianjinjia.zhishan.R;
import com.qianjinjia.zhishan.dialog.ProgressBarDialog;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.NumberFormat;

/**
* Created by Administrator on 2018/3/9.
*/

public class DownFileHelper {

Handler handler;
Context mContext;
NotificationManager mNotifyManager;
Notification.Builder builder;

public DownFileHelper(Context mContext, Handler handler) {
this.handler = handler;
this.mContext = mContext;
}

/**
* 下载最新版本的apk
*
* @param path apk下载地址
*/
public void downFile(final String path) {

mNotifyManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
Bitmap btm = BitmapFactory.decodeResource(mContext.getResources(), R.mipmap.app_icon);//可以换成你的app的logo
if (Build.VERSION.SDK_INT >= 26) {

//创建 通知通道 channelid和channelname是必须的(自己命名就好)
NotificationChannel channel = new NotificationChannel("1",
"Channel1", NotificationManager.IMPORTANCE_DEFAULT);
channel.enableLights(true);//是否在桌面icon右上角展示小红点
channel.setLightColor(Color.GREEN);//小红点颜色
channel.setShowBadge(true); //是否在久按桌面图标时显示此渠道的通知
mNotifyManager.createNotificationChannel(channel);

builder = new Notification.Builder(mContext, "1");
//设置通知显示图标、文字等
builder.setSmallIcon(R.mipmap.app_logo)//可以换成你的app的logo
.setLargeIcon(btm)
.setTicker("正在下载")
.setContentTitle("我的app")
.setAutoCancel(true)
.build();
mNotifyManager.notify(1, builder.build());

} else {
builder = new Notification.Builder(mContext);
builder.setSmallIcon(R.mipmap.app_logo)//可以换成你的app的logo
.setLargeIcon(btm)
.setTicker("正在下载")
.setContentTitle("我的app")
.setAutoCancel(true)//可以滑动删除通知栏
.build();
mNotifyManager.notify(1, builder.build());
}
new Thread() {
public void run() {
try {
URL url = new URL(path);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setReadTimeout(5000);
con.setConnectTimeout(5000);
con.setRequestProperty("Charset", "UTF-8");
con.setRequestMethod("GET");
if (con.getResponseCode() == 200) {
int length = con.getContentLength();// 获取文件大小
InputStream is = con.getInputStream();

FileOutputStream fileOutputStream = null;
if (is != null) {
//对apk进行保存
File file = new File(Environment.getExternalStorageDirectory()
.getPath(), "your_app_name.apk");
fileOutputStream = new FileOutputStream(file);
byte[] buf = new byte[1024];
int ch;
int process = 0;
NumberFormat numberFormat = NumberFormat.getInstance();
// 设置精确到小数点后2位
numberFormat.setMaximumFractionDigits(2);
String result;
while ((ch = is.read(buf)) != -1) {
fileOutputStream.write(buf, 0, ch);
process += ch;
//更新进度条
result = numberFormat.format((float) process / (float) length * 100);
builder.setContentText("下载进度:" + result + "%");
builder.setProgress(length, process, false);
mNotifyManager.notify(1, builder.build());

}
}
if (fileOutputStream != null) {
fileOutputStream.flush();
fileOutputStream.close();
}
//apk下载完成,使用Handler()通知安装apk
builder.setProgress(length, length, false);
builder.setContentText("已经下载完成");
mNotifyManager.notify(1, builder.build());
mNotifyManager.cancelAll();
handler.sendEmptyMessage(0);

}
} catch (Exception e) {
e.printStackTrace();
}
}

}.start();

}
}安装app的实现类,其中Android8.0安装时需要检测和申请app可安装未知来源权限允许,在AndroidManifest.xml添加
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>还有Android7.0之后文件共享需要使用FileProvider的功能,uri的获取不一样。具体看我的这篇博客 Android 7.0自动安装实现
package com.qianjinjia.zhishan.helper;

import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;

import android.support.v4.app.ActivityCompat;
import android.support.v4.content.FileProvider;

import com.qianjinjia.zhishan.BuildConfig;
import com.qianjinjia.zhishan.dialog.ConfirmDialog;

import java.io.File;
import java.io.IOException;

/**
* Created by Administrator on 2018/3/13.
*/

public class InstallApk {

Activity context;

public InstallApk(Activity context) {
this.context = context;
}

public void installApk(File apkFile) {
Intent intent = new Intent(Intent.ACTION_VIEW);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
boolean b = context.getPackageManager().canRequestPackageInstalls();
if (b) {
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Uri contentUri = FileProvider.getUriForFile(context.getApplicationContext(),
BuildConfig.APPLICATION_ID+".fileProvider", apkFile);
intent.setDataAndType(contentUri, "application/vnd.android.package-archive");
context.startActivity(intent);
} else {
//请求安装未知应用来源的权限
ConfirmDialog confirmDialog =new ConfirmDialog(context);
confirmDialog.setStyle("安装权限","Android8.0安装应用需要打开未\n知来源权限,请去设置中开启权限",
"去设置","取消");
confirmDialog.setClicklistener(new ConfirmDialog.ClickListenerInterface() {
@Override
public void doConfirm() {
String[] mPermissionList = new String[]{Manifest.permission.REQUEST_INSTALL_PACKAGES};
ActivityCompat.requestPermissions(context, mPermissionList, 2);
}
});
confirmDialog.show();
}
} else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Uri contentUri = FileProvider.getUriForFile(context.getApplicationContext(),
BuildConfig.APPLICATION_ID+".fileProvider", apkFile);
intent.setDataAndType(contentUri, "application/vnd.android.package-archive");
context.startActivity(intent);
} else {
intent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
}

}
}还需要个权限检测和权限申请的帮助类
package com.qianjinjia.zhishan.helper;

import android.app.Activity;
import android.content.pm.PackageManager;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.support.v4.app.ActivityCompat;

/**
* Created by Administrator on 2018/3/14.
*/
//权限检测和申请帮助类
public class PermissionHelper {
Activity activity;

public PermissionHelper(Activity activity) {
this.activity = activity;
}

/**
* 第 1 步: 检查是否拥有指定的所有权限
*/

public boolean checkPermissionAllGranted(String[] permissions) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
for (String permission : permissions) {
if (ActivityCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED) {
// 只要有一个权限没有被授予, 则直接返回 false
return false;
}
}
return true;
}
return true;
}

/**
* 第 2 步: 请求权限
*/
// 一次请求多个权限, 如果其他有权限是已经授予的将会自动忽略掉
public void requestPermissionAllGranted(String[] permissions, int i) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
ActivityCompat.requestPermissions(activity, permissions, i);
}
}

}然后在Activity里负责是否更新逻辑和下载所需要的权限申请和检测以及安装app的操作

public class MainActivity extends BaseActivity<MainPresenter> implements MainContract.View {

Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 0:
new InstallApk(MainActivity.this)
.installApk(new File(Environment.getExternalStorageDirectory(), "your_app_name.apk"));
break;
}

}
};

@Override
protected int getLayout() {
return R.layout.activity_main;
}

//这里是请求服务的是否更新接口返回数据的处理,你可以结合你自己后端的处理
@Override
public void updateonSuccess(UpdateBean bean) {
if (Integer.valueOf(bean.getData().getAndroid_version_index()) > SystemTool.getAppVersionCode(MyApplication._context)) {
url = bean.getData().getAndroid_download_url();
if (bean.getData().getAndroid_is_update() == 2) {
//更新版本
String today = DateUtils.getNowTime();
String days = (String) SpUtils.getParam(getApplicationContext(), "day", "");
if (!days.equals(today)) {
updateDialog(bean);
}
} else {
//强制更新版本
forcedUpdateDialog(bean);
}
}
}

private void forcedUpdateDialog(UpdateBean bean) {
aButtonDialog.setStyle("版本更新", bean.getData().getUpdate_desc(), "立即更新");
aButtonDialog.setClicklistener(new AButtonDialog.ClickListenerInterface() {
@Override
public void doConfirm() {
permissionsCheckAndDownload();

}
});
aButtonDialog.setOnKeyListener(new DialogInterface.OnKeyListener() {
@Override
public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {

if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {
aButtonDialog.dismiss();
android.os.Process.killProcess(android.os.Process.myPid()); //获取PID
System.exit(0); //常规java、c#的标准退出法,返回值为0代表正常退出
}
return false;
}
});
aButtonDialog.show();
}

private void updateDialog(UpdateBean bean) {
confirmDialog.setStyle("版本更新", bean.getData().getUpdate_desc(), "立即更新", "取消");
confirmDialog.setClicklistener(new ConfirmDialog.ClickListenerInterface() {
@Override
public void doConfirm() {
permissionsCheckAndDownload();

}
});
confirmDialog.setOnCancelClickListener(new ConfirmDialog.OnCancelClickListener() {
@Override
public void onCancelClick() {
String today = DateUtils.getNowTime();
SpUtils.put(getApplicationContext(), "day", today);
}
});
confirmDialog.show();
}

private void permissionsCheckAndDownload() {
if (Build.VERSION.SDK_INT >= 23) {
permissionsCheck();
} else {
new DownFileHelper(MainActivity.this, handler)
.downFile(url);
}

}

private void permissionsCheck() {
if (!permissionHelper.checkPermissionAllGranted(mPermissionList)) {
permissionHelper.requestPermissionAllGranted(mPermissionList, 1);
} else {
new DownFileHelper(MainActivity.this, handler)
.downFile(url);
}
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case 1:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
new DownFileHelper(MainActivity.this, handler)
.downFile(url);

} else {
//不给读写权限处理
}
break;
case 2:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
new InstallApk(MainActivity.this)
.installApk(new File(Environment.getExternalStorageDirectory(), "your_app_name.apk"));
} else {
Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES);
startActivityForResult(intent, 10012);
}
break;
}
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case 10012:
Log.d("resultCode", resultCode + "");
if (Build.VERSION.SDK_INT >= 26) {
boolean b = getPackageManager().canRequestPackageInstalls();
if (b) {
new InstallApk(MainActivity.this)
.installApk(new File(Environment.getExternalStorageDirectory(), "qianjinjia.apk"));
} else {
final AButtonDialog aButton = new AButtonDialog(MainActivity.this);
aButton.setStyle("您未打开未知来源\n权限不能及时更新", "知道了");
aButton.setClicklistener(new AButtonDialog.ClickListenerInterface() {
@Override
public void doConfirm() {

}
});
aButton.setOnKeyListener(new DialogInterface.OnKeyListener() {
@Override
public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {
aButton.dismiss();
android.os.Process.killProcess(android.os.Process.myPid()); //获取PID
System.exit(0); //常规java、c#的标准退出法,返回值为0代表正常退出
}
return false;
}
});
aButton.show();
}
}

break;

default:
break;
}
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐