android使用service在后台下载更新
阅读原文时间:2021年04月20日阅读:1

看了https://blog.csdn.net/baidu_34928905/article/details/88388082的文章,感觉不错,就自己试了一下,现在把代码放出来,以备后用
在使用时,我们先要做的准备是
一、权限 在AndroidManifest.xml中加入

<!-- 允许访问网络 -->
    <uses-permission android:name="android.permission.INTERNET" />
    <!-- 访问电话状态 -->
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <!-- 允许程序写入外部存储,如SD卡上写文件 -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <!-- 允许程序读取外部存储 -->
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <!--震动权限 -->
    <uses-permission android:name="android.permission.VIBRATE"></uses-permission>

这里要注意的是,对于文件的读写权限,你要在页面中动态的申请,这里可以根据自己使用的不同方法自己确定

//权限的设置
 myUntils.JudgePermission(this,this,"您拒绝了读取文件的功能,会造成软件无法更新下载,并且会影响到维修与巡更功能!",Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE);

二、我们知道,绝大多数国产Android App都会内置一个更新功能,也就是把新版本的APK放在服务器上,通过接口获取更新信息并下载,然后进行安装。虽然这种行为被Google严厉禁止,但身处这种环境下还是得妥协的。在android7.0之后,我们不能直接

Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");

而是要进行如下处理:
1、AndroidManifest中增加

<provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="${applicationId}.provider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/provider_paths" />
        </provider>

2、res下新建xml/provider_paths.xml

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="external_files" path="."/>
</paths>

好了,准备工作完成,开始我们的代码。
DownAPKService.java

public class DownAPKService extends Service {

    private final int NotificationID = 0X10000;
    private NotificationManager mNotificationManager = null;
    private NotificationCompat.Builder builder;

    //文件保存路径(如果有sd卡就保存sd卡,如果没有sd卡就保存到手机包名下的路径)
    private String Apk_dir = "";

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();

        //创建保存路径
        initAPKDir();
    }

    /**
     * 创建保存路径
     */
    private void initAPKDir() {
        /*
         * 创建路径的时候一定要用[/],不能使用[\],但是创建文件夹加文件的时候可以使用[\].
         * [/]符号是Linux系统路径分隔符,而[\]是windows系统路径分隔符 Android内核是Linux.
         */
        if(isHasSdcard())
        {
            //保存到sd卡
            Apk_dir = Environment.getExternalStorageDirectory().getAbsolutePath() + "/VersionChecker/";
        }else{
            //保存到app的包名路径下
            Apk_dir = getApplicationContext().getFilesDir().getAbsolutePath() + "/VersionChecker/";
        }

        File destDir = new File(Apk_dir);
        if(!destDir.exists())
        {
            destDir.mkdirs();
        }
    }

    /**
     * 判断是否插入sd卡
     * @return   true 有    false 无
     */
    private boolean isHasSdcard() {
        String status = Environment.getExternalStorageState();

        return status.equals(Environment.MEDIA_MOUNTED);
    }


    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        // 接收Intent传来的参数:
        // 文件下载路径
        String APK_URL = intent.getStringExtra("apk_url");
        String APK_Name = intent.getStringExtra("apk_name");

        DownFile(APK_URL, Apk_dir, APK_Name);

        return super.onStartCommand(intent, flags, startId);
    }

    private void DownFile(String apk_url,String apk_path, String apk_name) {


        OkGo.<File>get(apk_url)
                .tag(this)
                .execute(new FileCallback(apk_path,apk_name) {

                    @Override
                    public void onStart(Request<File, ? extends Request> request) {
                        super.onStart(request);
                        Log.e("DownAPKService.java(onStart)", "行数: 98  开始下载文件");
                        String id = "my_channel_01";
                        String name = "渠道的名字";
                        mNotificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);

                        // 针对Android 8.0版本对于消息栏的限制,需要加入channel渠道这一概念
                        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
                        {
                            //Android 8.0以上
                            NotificationChannel mChannel = new NotificationChannel(id,name,NotificationManager.IMPORTANCE_LOW);

                            mNotificationManager.createNotificationChannel(mChannel);
                            builder = new NotificationCompat.Builder(getApplicationContext());
                            builder.setSmallIcon(R.mipmap.ic_launcher);
                            builder.setTicker("正在下载新版本");
                            builder.setContentTitle(getApplicationName());
                            builder.setContentText("正在下载,请稍后...");
                            builder.setNumber(0);
                            builder.setChannelId(id);
                            builder.setAutoCancel(true);
                        }else{
                            builder = new NotificationCompat.Builder(getApplicationContext());
                            builder.setSmallIcon(R.mipmap.ic_launcher);
                            builder.setTicker("正在下载新版本");
                            builder.setContentTitle(getApplicationName());
                            builder.setContentText("正在下载,请稍后...");
                            builder.setNumber(0);
                            builder.setAutoCancel(true);
                        }

                        mNotificationManager.notify(NotificationID,builder.build());
                    }

                    @Override
                    public void onSuccess(Response<File> response) {
                        Log.e("DownAPKService.java(onSuccess)", "行数: 138  下载完成");
                        Intent installIntent = new Intent(Intent.ACTION_VIEW);
                        System.out.println(response.body().getPath());
                        Uri uri = Uri.fromFile(new File(response.body().getPath()));

                        installIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

                        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
                        {
                            installIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                            Uri uri1 = FileProvider.getUriForFile(getApplicationContext(), getApplicationContext().getPackageName() + ".provider", response.body());
                            installIntent.setDataAndType(uri1, "application/vnd.android.package-archive");

                        }else{
                            installIntent.setDataAndType(uri, "application/vnd.android.package-archive");
                        }

                        PendingIntent mPendingIntent = PendingIntent.getActivity(DownAPKService.this, 0, installIntent, 0);
                        builder.setContentText("下载完成,请点击安装");
                        builder.setContentIntent(mPendingIntent);
                        mNotificationManager.notify(NotificationID, builder.build());
                        // 震动提示
                        Vibrator vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
                        assert vibrator != null;
                        vibrator.vibrate(250L);// 参数是震动时间(long类型)
                        stopSelf();
                        startActivity(installIntent);// 下载完成之后自动弹出安装界面
                        mNotificationManager.cancel(NotificationID);

                    }

                    @Override
                    public void onError(Response<File> response) {
                        super.onError(response);
                        System.out.println("文件下载失败");
                        mNotificationManager.cancel(NotificationID);
                        Log.e("DownAPKService.java(onError)", "行数: 171  err:" + response.message());

                    }

                    @Override
                    public void downloadProgress(Progress progress) {
                        super.downloadProgress(progress);
                        int percent = (int)Math.floor(progress.fraction * 100);
                        int totalS = Long.valueOf(progress.totalSize).intValue();
                        builder.setProgress(totalS, percent, false);
                        if (percent < 0) {//遏制有负数的情况
                            percent = 0;
                        }
                        builder.setContentInfo(percent + "%");
                        mNotificationManager.notify(NotificationID, builder.build());

                    }
                });
    }

    /**
     * @return
     * @Description 获取当前应用的名称
     */
    private String getApplicationName() {
        PackageManager packageManager = null;
        ApplicationInfo applicationInfo = null;
        try {
            packageManager = getApplicationContext().getPackageManager();
            applicationInfo = packageManager.getApplicationInfo(getPackageName(), 0);
        } catch (PackageManager.NameNotFoundException e) {
            applicationInfo = null;
        }
        String applicationName = (String) packageManager.getApplicationLabel(applicationInfo);
        return applicationName;
    }


    @Override
    public void onDestroy() {
        super.onDestroy();
        stopSelf();
    }
}

mainactivity.java中调用

String apk_url = "http://XXXXXX/home.apk";
                Intent intent = new Intent();
                intent.putExtra("apk_url",apk_url);
                intent.putExtra("apk_name","home.apk");
                intent.setClass(MainActivity.this,DownAPKService.class);
                startService(intent);

最后,你要在Androidmanifest.xml中注册这个service

<service android:name=".services.DownAPKService"/>

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器