首先下载问文件需要在AndroidManifest.xml里添加SD卡读写权限,下面两个权限:

android:name="android.permission.WRITE_EXTERNAL_STORAGE" />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添加

还有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 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;        }    }  }




更多相关文章

  1. Android应用程序签名和权限增强应用程序安全性
  2. android运行时权限解决办法(含有申请权限已授权、权限被拒绝、权
  3. Android中的权限机制
  4. Android(安卓)Wear 之 为通知添加动作
  5. 利用adb无线连接android手机进行调式 无需获得root权限
  6. Android(安卓)Q(10.0)版本新特性以及兼容性适配
  7. Android开发指南-框架主题-安全和许可
  8. Android(安卓)6.0运行时权限勾选不再询问后该如何处理?
  9. Android(安卓)获取Root权限之后的静默安装实现 代码示例分析

随机推荐

  1. java 中 写 json 小知识
  2. Intellij IDEA和JavaFX工件构建不会生成E
  3. Java NIO- Selector 使用示例
  4. 用 Java 模拟 UDP 传输的发送端和接收端
  5. Java Quartz的使用方法,实现程序计时
  6. 环境变量在cron中看不到
  7. 将行计数器方法与字数统计方法相结合
  8. java小练习(一个数如果恰好等于它的因子之
  9. Java调用gc机制强制删除文件
  10. 将日期保存到序列化文件