今天的是用okhttp 实现应用下载
- 需要的权限和依赖
权限
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
依赖
implementation 'com.squareup.okhttp3:okhttp:3.10.0'//okhttp3
- 工具类
public class InstallUtil {
public static final int UNKNOWN_CODE = 2019;
public static void installApk(Context context, String path) {
if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){
startInstallO(context,path);
}else if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.N){
startInstallN(context,path);
}else {
startInstall(context,path);
}
}
/**
*android1.x-6.x
*@param path 文件的路径
*/
private static void startInstall(Context context, String path) {
Intent install = new Intent(Intent.ACTION_VIEW);
install.setDataAndType(Uri.parse("file://" + path), "application/vnd.android.package-archive");
install.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(install);
}
/**
* android7.x
* @param path 文件路径
*/
@RequiresApi(api = Build.VERSION_CODES.N)
private static void startInstallN(Context context, String path) {
//参数1 上下文, 参数2 在AndroidManifest中的android:authorities值, 参数3 共享的文件
Uri apkUri = FileProvider.getUriForFile(context, "com.baidu.download.provider", new File(path));
Intent install = new Intent(Intent.ACTION_VIEW);
//由于没有在Activity环境下启动Activity,设置下面的标签
install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//添加这一句表示对目标应用临时授权该Uri所代表的文件
install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
install.setDataAndType(apkUri, "application/vnd.android.package-archive");
context.startActivity(install);
}
/**
* android8.x
*/
@RequiresApi(api = Build.VERSION_CODES.O)
private static void startInstallO(final Context context, String path) {
boolean isGranted = context.getPackageManager().canRequestPackageInstalls();
if (isGranted) startInstallN(context,path);//安装应用的逻辑(写自己的就可以)
else new AlertDialog.Builder(context)
.setCancelable(false)
.setTitle("安装应用需要打开未知来源权限,请去设置中开启权限")
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface d, int w) {
Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES);
Activity act = (Activity) context;
act.startActivityForResult(intent, UNKNOWN_CODE);
}
})
.show();
}
}
- activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/btn1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="ok" />
</android.support.constraint.ConstraintLayout>
- MainActivity.java
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
/**
* ok
*/
private Button mBtn1;
private File mSd;
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initSD();
}
private void initSD() {
// 判断该程序中是否有写入的权限
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED) {
// 如果有,调用方法,获取到sd卡的全路径
openSD();
} else {
// 如果没有,获取到该权限
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 100);
}
}
/**
* 请求权限成功的结果
*
* @param requestCode
* @param permissions
* @param grantResults
*/
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == 100 && grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
openSD();
}
}
private void openSD() {
// Environment拥有一些可以获取环境变量的方法
// 判断外部存储状态是否为安装的状态
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
// 获取到sd卡的路劲
mSd = Environment.getExternalStorageDirectory();
}
}
private void initView() {
mBtn1 = (Button) findViewById(R.id.btn1);
mBtn1.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
default:
break;
case R.id.btn1:
ok();
break;
}
}
private void ok() {
// 获取到OkHttpClient 的对象
OkHttpClient client = new OkHttpClient.Builder()
.build();
// 构建Request的对象
Request request = new Request.Builder()
.url("http://cdn.banmi.com/banmiapp/apk/banmi_330.apk")
.get()
.build();
// 构建Call对象
Call call = client.newCall(request);
// 开启异步请求
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.d(TAG, "onFailure: " + e.getMessage());
}
@Override
public void onResponse(Call call, Response response) throws IOException {
// 通过响应获取到响应体
ResponseBody body = response.body();
// 在通过响应体获取 输入流
InputStream inputStream = body.byteStream();
saveFile(inputStream, mSd + "/" + "acb123.apk", body.contentLength());
}
});
}
/**
* @param inputStream 输入流
* @param s 安装程序的地址
* @param max 安装的程序的总长度
*/
private void saveFile(InputStream inputStream, final String s, long max) {
// 读写进度
long count = 0;
try {
// 实例化一个文件输出流
FileOutputStream fileOutputStream = new FileOutputStream(new File(s));
int length = -1;
byte[] bytes = new byte[1024 * 1000];
while ((length = inputStream.read(bytes)) != -1) {
// 根据指定的长度,来写入数据
fileOutputStream.write(bytes, 0, length);
// 写入数据的进度
count += length;
Log.d(TAG, "progress: " + count + ",max:" + max);
}
// 关闭输入流
inputStream.close();
// 关闭输出流
fileOutputStream.close();
// 在主线程中运行
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, "下载完成", Toast.LENGTH_SHORT).show();
// 安装apk
InstallUtil.installApk(MainActivity.this, s);
}
});
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
网友评论