Android 实现通知栏通知APP版本更新

前言:

我们似乎在做什么apk,都需要去做更新这个功能,那怎么去做这个功能才好呢,那当然在做的时候当然回去百度一下(除非是大神)。想我这个种没做一个比较好玩的功能的时候,第一步就是去百度大家的做法,想法。怎么去实现、怎么完成。怎样比较好看,和健壮性比较好。

一直一来自己都是小白,所以很明白小白的心情,自己写博客也会写的非常详细,希望大神勿喷。也希望小白能从中得到学习。

好了不啰嗦,马上开始我们的代码体验.


为了不浪费大家的时间,我们先开看一下我们的实现效果先.如果这个效果是你想要的.就可以仔细阅读一下本篇文章啦.





正文:

这个自动检测升级Apk的功能,相信每个应用都会使用到。这里也提供给大家使用,直接copy过去就能使用了。

不需要做过多的调整。 

其中使用Service、BroadcastReceiver、OkHttp下载、Gson解析json、NotificationManager、Notification 运用的知识也挺多的,也可以供大家参考、学习使用。


          源码下载:点击打开链接           模拟json数据下载:点击打开链接            模拟APK下载:点击打开链接


注意:博主使用的是Tomcat服务器,我们将这些数据下载下来放在Tomcat服务上就可以测试了


好了接下在直接进入代码主题:

      1、第一步先添加入所需要的第三方依赖



      2、模拟写好要去读取的json数据(这里可以是xml数据,根据自己喜欢)


update.json

{  
    //app名字  
    appname:"UpdateApk",  
    //服务器版本号  
    serverVersion:2,  
    //是否强制更新  true为强制升级,false为正常状态  
    whetherForce:false,  
    //apk下载地址  
    updateurl:"http://127.0.0.1:8080/UpdateApk.apk",  
    //版本的更新的描述  
    upgradeinfo:"有新功能哦!要不要尝试一下"  
  
}


3、写好对应的Bean类   


UpdateInfo.java


public class UpdateInfo {

    //app名字
    private String appname;
    //服务器版本
    private int serverVersion;
    //强制升级
    private boolean whetherForce;
    //app最新版本地址
    private String updateurl;
    //升级信息
    private String upgradeinfo;

    /**
     * 都生成对于的set and get 方法
     * 这里我就不把set and get 方法贴出来了,读者注意去生成就好了
     */
    
}



4、单独创建一个java类来存储存放json数据的连接(方便管理)


HttpApi.java


/**
 * 这里存放我们要去读取的json数据连接
 */
public class HttpApi {
    public static String updateUrl = "http://127.0.0.1:8080/updateapk.json";
}


5、创建MyApplication.java 去继承 Application。需要一进去APP就去请求网络进行APP版本信息比配


/**
 * 在程序进入的时候我们就去读取网络上APK的信息
 * Created by WL-鬼 on 2017/5/13.
 */

public class MyApplication extends Application {

    //先在这创建好上下文环境,可能会使用到,这里为个人习惯,需要使用的时候在创建也是可以的
    private static Context mContext;
    //读取到的bean对象
    private static UpdateInfo mUpdateInfo;

    public static final String UPDATE_ACTION = "UPDATE_INFO";


    @Override
    public void onCreate() {
        super.onCreate();
        mContext = this.getApplicationContext();

        getServiceUpdateInfo(false);

    }

    /**
     * 获取服务器上的更新信息
     * @param isClick  参数一:是否为手动点击的检测更新
     * @return         获取到的UpdateInfo对象
     */
    public static UpdateInfo getServiceUpdateInfo(final boolean isClick){
        mUpdateInfo = new UpdateInfo();
        new Runnable() {
            @Override
            public void run() {
                OkHttpClient mOkHttpClient = new OkHttpClient();
                Request mRequest = new Request.Builder().url(HttpApi.updateUrl).build();

                Call mCall = mOkHttpClient.newCall(mRequest);

                Callback callback = new Callback()  {
                    @Override
                    public void onFailure(Call call, IOException e) {
                        String r = e.toString();
                        Log.d("onFailure",r);
                    }

                    @Override
                    public void onResponse(Call call, Response response) {
                        Log.d("MyApplication--onResponse",response.code()+"");
                        try {
                            //只有服务器已成功处理了请求,才继续处理我们接下来想处理的事情
                            if (response.code() == 200){
                                String infoStr = response.body().string();
                                Log.d("onResponse",infoStr);
                                Gson mGson = new Gson();
                                mUpdateInfo = mGson.fromJson(infoStr,UpdateInfo.class);
                                //创建Intent
                                Intent intent = new Intent(UPDATE_ACTION);
                                if (isClick){
                                    intent.putExtra("isclick",isClick);
                                }
                                //开启广播
                                mContext.sendBroadcast(intent);
                            }
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                };
                mCall.enqueue(callback);
            }
        }.run();
        return mUpdateInfo;
    }

    public static UpdateInfo getmUpdateInfo() {
        return mUpdateInfo;
    }

    public static Context getContext() {
        return mContext;
    }
}


6、去创建 UpdateReceiver 继承 BroadcastReceiver 并且需要注册(这里可以使用动态注册和静态注册)(我这里实现了静态注册)

6.1、在UpdateReceiver中所需要使用到的布局文件

download_promp.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:padding="8dp"
    android:id="@+id/download_notification_root"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">

        <ImageView
            android:id="@+id/download_promp_icon"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

        <LinearLayout
            android:orientation="vertical"
            android:layout_marginLeft="10dp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content">

            <TextView
                android:id="@+id/download_title"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" />

            <TextView
                android:id="@+id/download_promp_info"
                android:paddingTop="8dp"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" />

        </LinearLayout>

</LinearLayout>



6.2,这里插入写的一个工具类


MyUtils.java

public class MyUtils {

    //放在下载更新包的文件夹
    public static String updateDownloadDir = "updateApk";

    /**
     * 获取本地APK的版本信息
     */
    public static int getLocalCodeVersion(){
        PackageManager mPackageManager = null;
        PackageInfo mPackageInfo = null;
        int localCodeEdition = 0;
        try {
            mPackageManager = getContext().getPackageManager();
            mPackageInfo =mPackageManager.getPackageInfo(getContext().getPackageName(),0);
            localCodeEdition = mPackageInfo.versionCode;
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        return localCodeEdition;
    }

    /**
     * 删除更新包
     */
    public static void clearUpateApk() {
        File updateDir;
        File updateFile;
        if (Environment.MEDIA_MOUNTED.equals(Environment
                .getExternalStorageState())) {
            updateDir = new File(Environment.getExternalStorageDirectory(),
                    updateDownloadDir);
        } else {
            updateDir = getContext().getFilesDir();
        }
        updateFile = new File(updateDir.getPath(),getContext().getResources()
                .getString(R.string.app_name) + ".apk");
        if (updateFile.exists()) {
            Log.d("update", "升级包存在,删除升级包");
            updateFile.delete();
        } else {
            Log.d("update", "升级包不存在,不用删除升级包");
        }
    }

}


注:我这个服务里面。提供了两种提示更新的方式一个是使用Dialog ,一个是使用通知拦方式(NotificationManager)可根据自己喜欢调用对应的方法。


public class UpdateReceiver extends BroadcastReceiver {

    //Dialog弹框
    private static AlertDialog.Builder mDialog;
    //这个是用来是否为手动点击获取更新信息的 默认为false
    private static boolean isClick = false;
    //刚刚在App中获取到的信息
    private static UpdateInfo mUpdateInfo;

    @Override
    public void onReceive(Context context, Intent intent) {
        //获取到网络上apk的信息
        mUpdateInfo = MyApplication.getmUpdateInfo();

        //获取是否为手动点击的信息 默认为false自动检测,true 为手动检测
        isClick = intent.getBooleanExtra("isclick",false);

        checkVersion(context);
    }

    /**
     * 检查版本更新
     */
    public void checkVersion(Context context) {
        //如果服务上的版本大于本地的版本
        if (mUpdateInfo.getServerVersion() > MyUtils.getLocalCodeVersion()){
            Log.d("版本更新","需要更新");
            //判断是否为强制更新
            if (mUpdateInfo.isWhetherForce()){// true 为是强制升级
                promptDiglog(context,2);
            }else {                            //false 为正常升级
                if (isClick){
                    promptDiglog(context,1);
                }else {
                    promptUpdate(context);
                }
            }
        }else{
            if (isClick){
                promptDiglog(context,0);
                Log.d("版本更新","无需更新");
            }
        }
        //判断是否存在升级包,存在就删除
        MyUtils.clearUpateApk();
    }

    /**
     *  通知栏提示更新
     */
    private void promptUpdate(Context context){
        NotificationManager motificationManager = (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE);
        Notification notification = new Notification();
        notification.icon = R.mipmap.ic_launcher_round;
        //添加声音提示
        notification.defaults = Notification.DEFAULT_SOUND;
        /* 或者使用以下几种方式
         * notification.sound = Uri.parse("file:///sdcard/notification/ringer.mp3");
         * notification.sound = Uri.withAppendedPath(Audio.Media.INTERNAL_CONTENT_URI, "6");
         * 如果想要让声音持续重复直到用户对通知做出反应,则可以在notification的flags字段增加"FLAG_INSISTENT"
         * 如果notification的defaults字段包括了"DEFAULT_SOUND"属性,则这个属性将覆盖sound字段中定义的声音
         */
        //audioStreamType的值必须AudioManager中的值,代表响铃模式
        notification.audioStreamType = AudioManager.ADJUST_LOWER;
        //添加LED灯提醒
        notification.defaults |= Notification.DEFAULT_LIGHTS;
        //或者可以自己的LED提醒模式:
        /*notification.ledARGB = 0xff00ff00;
        notification.ledOnMS = 300; //亮的时间
        notification.ledOffMS = 1000; //灭的时间
        notification.flags |= Notification.FLAG_SHOW_LIGHTS;*/
        //添加震动
        notification.defaults |= Notification.DEFAULT_VIBRATE;
        //或者可以定义自己的振动模式:
        /*long[] vibrate = {0,100,200,300}; //0毫秒后开始振动,振动100毫秒后停止,再过200毫秒后再次振动300毫秒
        notification.vibrate = vibrate;*/
        //状态栏提示信息
        notification.tickerText = mUpdateInfo.getAppname()+" 发现新版本,点击下载";
        //获取当前时间
        notification.when = System.currentTimeMillis();
        //加载自定义布局
        notification.contentView = getRemoteViews(context,"发现新版本,点击下载");
        //加载点击事件
        notification.contentIntent = getPendingIntent(context);
        // 点击清除按钮或点击通知后会自动消失
        notification.flags |= Notification.FLAG_AUTO_CANCEL;
        //取消Intent事件
        //notification.contentIntent.cancel();
        motificationManager.notify(0, notification);

    }

    //自定义notification布局
    public static RemoteViews getRemoteViews(Context context,String info) {
        RemoteViews remoteviews = new RemoteViews(context.getPackageName(),R.layout.download_promp);
        remoteviews.setImageViewResource(R.id.download_promp_icon,R.mipmap.ic_launcher_round);
        remoteviews.setTextViewText(R.id.download_title,mUpdateInfo.getAppname());
        remoteviews.setTextViewText(R.id.download_promp_info,info);
        //如果你需要对title中的哪一个小控件添加点击事件可以这样为控件添加点击事件(详情请下载代码进行观看)
        //remoteviews.setOnClickPendingIntent(R.id.download_notification_root,getPendingIntent(context));
        return remoteviews;
    }

    /**
     * 给通知栏添加点击事件,实现具体操作
     * @param context 上下文
     * @return
     */
    private PendingIntent getPendingIntent(Context context) {
        Intent intent = new Intent(context,UpdateService.class);
        intent.addFlags(FLAG_ACTIVITY_NEW_TASK);
        intent.putExtra("appname",mUpdateInfo.getAppname());
        intent.putExtra("updateurl",mUpdateInfo.getUpdateurl());
        PendingIntent pendingIntent = PendingIntent.getService(context,0,intent,0);
        return pendingIntent;
    }

    /**
     * Dialog提示升级,用户可以选择是否取消升级
     */
    private void promptDiglog(final Context context, int i) {

        mDialog = new AlertDialog.Builder(context);
        mDialog.setTitle("版本更新");
        switch (i){
            case 0:  //没有升级的版本
                mDialog.setMessage("当前为最新版本");
                mDialog.setNegativeButton("确定", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                    }
                });
                break;
            case 1:   //正常升级
                mDialog.setMessage(mUpdateInfo.getUpgradeinfo());
                mDialog.setPositiveButton("去升级", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        Intent mIntent = new Intent(context, UpdateService.class);
                        mIntent.addFlags(FLAG_ACTIVITY_NEW_TASK);
                        mIntent.putExtra("appname",mUpdateInfo.getAppname());
                        mIntent.putExtra("updateurl",mUpdateInfo.getUpdateurl());
                        //传递数据
                        context.startService(mIntent);
                    }
                }).setNegativeButton("下次吧", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                    }
                });
                break;
            case 2:  //强制升级
                mDialog.setMessage(mUpdateInfo.getUpgradeinfo());
                mDialog.setPositiveButton("升级", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        Intent mIntent = new Intent(context, UpdateService.class);
                        mIntent.addFlags(FLAG_ACTIVITY_NEW_TASK);
                        mIntent.putExtra("appname",mUpdateInfo.getAppname());
                        mIntent.putExtra("updateurl",mUpdateInfo.getUpdateurl());
                        //启动服务
                        context.startService(mIntent);
                    }
                }).setNegativeButton("退出", new DialogInterface.OnClickListener() {

                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        // 直接退出应用
                        System.exit(0);
                    }
                });
                break;
        }
        AlertDialog alertDialog = mDialog.create();
        alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_TOAST);
        alertDialog.show();
    }
}

 


注:AndroidManifest.xml 中注册的广播代码


        <!-- 静态注册广播 -->
        <receiver android:name=".Receiver.UpdateReceiver">
            <intent-filter>
                <action android:name="UPDATE_INFO"/>
            </intent-filter>
        </receiver>


7、创建UpdateService 继承 Sercive 同样这个服务也需要注册。


download_notification.xml   在 Service  中使用到的布局

 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:orientation="vertical"
    android:layout_height="match_parent">


    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <TextView
            android:id="@+id/download_notice_name_tv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"/>
        <TextView
            android:id="@+id/download_notice_speed_tv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"
            android:layout_toRightOf="@+id/download_notice_name_tv"/>

    </LinearLayout>

    <ProgressBar
        android:id="@+id/pbProgress"
        style="@style/Widget.AppCompat.ProgressBar.Horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="5dp"/>
</LinearLayout>



UpdateService.java


/**
 * 状态栏通知服务
 * Created by WL-鬼 on 2017/5/13.
 */

public class UpdateService extends Service{


    private static final float SIZE_BT = 1024L; // BT字节参考量
    private static final float SIZE_KB = SIZE_BT * 1024.0f; // KB字节参考量
    private static final float SIZE_MB = SIZE_KB * 1024.0f;// MB字节参考量

    private final static String DOWNLOAD_COMPLETE = "1";// 完成
    private final static String DOWNLOAD_NOMEMORY = "-1";// 内存异常
    private final static String DOWNLOAD_FAIL = "-2";// 失败

    private String appName = null;// 应用名字
    private String appUrl = null;// 应用升级地址
    private File updateDir = null;// 文件目录
    private File updateFile = null;// 升级文件

    private NotificationManager updateNotificationManager = null; // 通知栏
    private Notification updateNotification = null;
    private PendingIntent updatePendingIntent = null;// 在下载的时候


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

    @Override
    public void onStart(Intent intent, int startId) {
        super.onStart(intent, startId);

        appName = intent.getStringExtra("appname");
        appUrl = intent.getStringExtra("updateurl");

        Log.d("UpdateService---------updateInfo",appName + "  " + appUrl);

        updateNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        updateNotification = new Notification();
        updateNotification.icon = R.mipmap.ic_launcher;//通知图标
        updateNotification.tickerText = "正在下载"+appName;//通知信息描述
        updateNotification.when = System.currentTimeMillis();
        updateNotification.contentView = new RemoteViews(getPackageName(),
                R.layout.download_notification);
        updateNotification.contentView.setTextViewText(
                R.id.download_notice_name_tv, appName + " 正在下载");
        new UpdateThread().execute();

    }

    /**
     * 这里使用一个内部类去继承AsyncTask
     * 实现异步操作
     */
    class UpdateThread extends AsyncTask{

        @Override
        protected Object doInBackground(Object[] params) {
            return  downloadUpdateFile(appUrl);
        }
    }

    private long totalSize;      //APK总大小
    private long downloadSize;  // 下载的大小
    private int count = 0;       //下载百分比

    /**
     *  下载更新程序文件
     * @param appUrl  下载地址
     * @return
     */
    private String downloadUpdateFile(String appUrl) {

        OkHttpClient mOkHttpClient = new OkHttpClient();

        Request mRequest = new Request.Builder().url(appUrl).build();

        Call mCall = mOkHttpClient.newCall(mRequest);

        mCall.enqueue(new Callback() {

            @Override
            public void onFailure(Call call, IOException e) {
                downloadResult(DOWNLOAD_FAIL);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if (response.code() == 200){
                    InputStream is = null;
                    byte[] buf = new byte[4096];
                    int len = 0;
                    FileOutputStream fos = null;
                    try {
                        totalSize = response.body().contentLength();
                        downloadSize  = 0;
                        if (MemoryAvailable(totalSize)){
                            is = response.body().byteStream();
                            fos = new FileOutputStream(updateFile,true);
                            while ((len = is.read(buf)) != -1) {
                                downloadSize  += len;
                                fos.write(buf, 0, len);
                                if ((count == 0) || (int) (downloadSize * 100 / totalSize) >= count) {
                                    count += 5;
                                    //文本进度(百分比)
                                    updateNotification.contentView
                                            .setTextViewText(
                                                    R.id.download_notice_speed_tv,
                                                    getMsgSpeed(downloadSize,totalSize));
                                    //进度条
                                    updateNotification.contentView.setProgressBar(
                                            R.id.pbProgress,
                                            (int)  totalSize,(int) downloadSize,false);
                                    updateNotificationManager.notify(0,updateNotification);
                                }
                            }
                            fos.flush();
                            if (totalSize >= downloadSize) {
                                //进度条
                                updateNotification.contentView.setProgressBar(
                                        R.id.pbProgress,
                                        (int)  totalSize,(int) totalSize,false);
                                downloadResult(DOWNLOAD_COMPLETE);
                            } else {
                                downloadResult(DOWNLOAD_FAIL);
                            }
                        }else {
                            downloadResult(DOWNLOAD_NOMEMORY);
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                        downloadResult(DOWNLOAD_FAIL);
                    } finally {
                        try {
                            if (is != null) {
                                is.close();
                            }
                            if (fos != null) {
                                fos.close();
                            }
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }else {
                    downloadResult(DOWNLOAD_FAIL);
                }
            }
        });
        return null;
    }


    /**
     * 下载结果
     * @param integer
     */
    private void downloadResult(String integer) {
        switch (integer){
            case DOWNLOAD_COMPLETE:
                Log.d("update","下载成功");
                String cmd = "chmod 777" + updateFile.getPath();
                try {
                    Runtime.getRuntime().exec(cmd);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                Uri uri = Uri.fromFile(updateFile);
                //安装程序
                Intent installIntent = new Intent(Intent.ACTION_VIEW);
                installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                installIntent.setDataAndType(uri,"application/vnd.android.package-archive");
                updatePendingIntent = PendingIntent.getActivity(UpdateService.this, 0, installIntent, 0);
                updateNotification.contentIntent = updatePendingIntent;
                updateNotification.tickerText = appName + " 下载完成";//通知信息描述
                /**
                 * 这里做为保留,是选择显示之前有进度条的下载完成提示还是选择另外的显示样式,可根据自己定义
                 */
//                updateNotification.contentView.setTextViewText(
//                        R.id.download_notice_name_tv, appName + " 下载完成");
//                updateNotification.contentView.setTextViewText(
//                        R.id.download_notice_speed_tv,
//                        getString(R.string.update_notice_install));
                updateNotification.contentView = UpdateReceiver.getRemoteViews(MyApplication.getContext(),"下载完成,点击安装");
                updateNotification.when = System.currentTimeMillis();
                updateNotification.defaults = Notification.DEFAULT_SOUND;
                updateNotification.flags |= Notification.FLAG_AUTO_CANCEL;
                updateNotificationManager.notify(0, updateNotification);
                //启动安装程序
                startActivity(installIntent);
                stopSelf();
                break;

            case DOWNLOAD_NOMEMORY:
                //如果内存有问题
                updateNotification.tickerText = appName + "下载失败";
                updateNotification.when = System.currentTimeMillis();
                updateNotification.contentView.setTextViewText(
                        R.id.download_notice_speed_tv,
                        getString(R.string.update_notice_nomemory));
                updateNotification.flags |= Notification.FLAG_AUTO_CANCEL;
                updateNotification.defaults = Notification.DEFAULT_SOUND;
                updateNotificationManager.notify(0, updateNotification);
                stopSelf();
                break;

            case DOWNLOAD_FAIL:
                //下载失败
                updateNotification.tickerText = appName + "下载失败";
                updateNotification.when = System.currentTimeMillis();
                updateNotification.contentView.setTextViewText(
                        R.id.download_notice_speed_tv,
                        getString(R.string.update_notice_error));
                updateNotification.flags |= Notification.FLAG_AUTO_CANCEL;
                updateNotification.defaults = Notification.DEFAULT_SOUND;
                updateNotificationManager.notify(0, updateNotification);
                stopSelf();
                break;
        }
    }

    /**
     * 可用内存大小
     * @param fileSize
     * @return
     */
    private boolean MemoryAvailable(long fileSize) {
        fileSize += (1024 << 10);
        if (MemoryStatus.externalMemoryAvailable()) {
            if ((MemoryStatus.getAvailableExternalMemorySize() <= fileSize)) {
                if ((MemoryStatus.getAvailableInternalMemorySize() > fileSize)) {
                    createFile(false);
                    return true;
                } else {
                    return false;
                }
            } else {
                createFile(true);
                return true;
            }
        } else {
            if (MemoryStatus.getAvailableInternalMemorySize() <= fileSize) {
                return false;
            } else {
                createFile(false);
                return true;
            }
        }
    }

    /**
     * 获取下载进度
     * @param downSize
     * @param allSize
     * @return
     */
    public static String getMsgSpeed(long downSize, long allSize) {
        StringBuffer sBuf = new StringBuffer();
        sBuf.append(getSize(downSize));
        sBuf.append("/");
        sBuf.append(getSize(allSize));
        sBuf.append(" ");
        sBuf.append(getPercentSize(downSize, allSize));
        return sBuf.toString();
    }

    /**
     * 获取大小
     * @param size
     * @return
     */
    public static String getSize(long size) {
        if (size >= 0 && size < SIZE_BT) {
            return (double) (Math.round(size * 10) / 10.0) + "B";
        } else if (size >= SIZE_BT && size < SIZE_KB) {
            return (double) (Math.round((size / SIZE_BT) * 10) / 10.0) + "KB";
        } else if (size >= SIZE_KB && size < SIZE_MB) {
            return (double) (Math.round((size / SIZE_KB) * 10) / 10.0) + "MB";
        }
        return "";
    }

    /**
     * 获取到当前的下载百分比
     * @param downSize   下载大小
     * @param allSize    总共大小
     * @return
     */
    public static String getPercentSize(long downSize, long allSize) {
        String percent = (allSize == 0 ? "0.0" : new DecimalFormat("0.0")
                .format((double) downSize / (double) allSize * 100));
        return "(" + percent + "%)";
    }

    /**
     * 创建file文件
     * @param sd_available    sdcard是否可用
     */
    private void createFile(boolean sd_available) {
        if (sd_available) {
            updateDir = new File(Environment.getExternalStorageDirectory(),
                    MyUtils.updateDownloadDir);
        } else {
            updateDir = getFilesDir();
        }
        updateFile = new File(updateDir.getPath(), appName + ".apk");
        if (!updateDir.exists()) {
            updateDir.mkdirs();
        }
        if (!updateFile.exists()) {
            try {
                updateFile.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            updateFile.delete();
            try {
                updateFile.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}



AndroidManifest.xml   中注册服务的代码

        <!-- 注册服务 -->
        <service
            android:name=".Service.UpdateService"
            android:enabled="true"
            android:exported="true">
        </service>


8、记得添加权限联网权限、sd卡读写权限...等等


    <!-- 联网 -->
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
    <!-- SD卡读写权限-->
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <!-- 卸载应用权限 -->
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
    <!-- 震动权限 -->
    <uses-permission android:name="android.permission.VIBRATE" />
    <!-- 应用静默安装  静默安装的代码我就没有提供了,大家可以上网搜索一下应该不会很难的 -->
    <uses-permission android:name="android.permission.INSTALL_PACKAGES" />
    <uses-permission android:name="android.permission.DELETE_PACKAGES"/>
    <uses-permission android:name="android.permission.CLEAR_APP_CACHE"/>
    <uses-permission android:name="android.permission.CLEAR_APP_USER_DATA"/>
    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>



9、在贴出我在开发用到的其它类和方法了。


MemoryStatus,java


/**
 * 完成代码的健壮性,其实现在的Android手机的储存都的够用的。
 * 一般不会没有空间,有这个类来判断就更健壮一些
 */
public class MemoryStatus {
    private static final int ERROR = -1;

    // 判断SD卡是否存在?
    static public boolean externalMemoryAvailable() {
        return Environment.getExternalStorageState().equals(
                Environment.MEDIA_MOUNTED);
    }

    // 获取内部存储器有用空间大小?
    static public long getAvailableInternalMemorySize() {
        File path = Environment.getDataDirectory();
        StatFs stat = new StatFs(path.getPath());
        long blockSize = stat.getBlockSize();
        long availableBlocks = stat.getAvailableBlocks();
        return availableBlocks * blockSize;
    }

    // 获取内部存储器空间的大小
    static public long getTotalInternalMemorySize() {
        File path = Environment.getDataDirectory();
        StatFs stat = new StatFs(path.getPath());
        long blockSize = stat.getBlockSize();
        long totalBlocks = stat.getBlockCount();
        return totalBlocks * blockSize;
    }

    // 获取SD卡有用空间大小,错误返回-1
    static public long getAvailableExternalMemorySize() {
        if (externalMemoryAvailable()) {
            File path = Environment.getExternalStorageDirectory();
            StatFs stat = new StatFs(path.getPath());
            long blockSize = stat.getBlockSize();
            long availableBlocks = stat.getAvailableBlocks();
            return availableBlocks * blockSize;
        } else {
            return ERROR;
        }
    }

    // 获取SD卡的空间大小,错误返码1
    static public long getTotalExternalMemorySize() {
        if (externalMemoryAvailable()) {
            File path = Environment.getExternalStorageDirectory();
            StatFs stat = new StatFs(path.getPath());
            long blockSize = stat.getBlockSize();
            long totalBlocks = stat.getBlockCount();
            return totalBlocks * blockSize;
        } else {
            return ERROR;
        }
    }

    /**
     * 根据给定的文件的路径来计算文件夹的大小
     * 
     * @param dir  文件的路径
     * @return 文件夹的大小
     */
    static public long getFileSize(File dir) {
        if (dir == null) {
            return 0;
        }
        if (!dir.isDirectory()) {
            return 0;
        }
        long dirSize=0;
        File[] files=dir.listFiles();
        for (File file : files) {
            if(file.isFile())
            {
                dirSize+=file.length();
            }else if (file.isDirectory()) {
                dirSize+=getFileSize(file); //如果是目标那就进行递归 来计算文件的大小
            }
        }
        return dirSize;
    }

    // 把文件大小转化字符串
    static public String formatSize(long size) {
        Log.d("WL-gui", "文件的大小为:"+size);
        String suffix = null;

        if(size==0)
        {
            return "";
        }

        if (size >= 1024) {
            suffix = "KB";
            size /= 1024;
            if (size >= 1024) {
                suffix = "MB";
                size /= 1024;
                if (size >= 1024) {
                    suffix = "G";
                    size /= 1024;
                }
            }
        }
        StringBuilder resultBuffer = new StringBuilder(Long.toString(size));
        int commaOffset = resultBuffer.length() - 3;
        while (commaOffset > 0) {
            resultBuffer.insert(commaOffset, ',');
            commaOffset -= 3;
        }
        if (suffix != null)
            resultBuffer.append(suffix);
        return resultBuffer.toString();
    }
}




好了到这,后台知道检测提示更新的代码已经展示完了。接下载就展示一下手动检测的,只需要一行代码就可以了。


第一步:只需要布局文件中添加个按钮(做为演示使用)


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="com.updateaapk.updateapk.MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="第一个版本"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />


    <Button
        android:text="检测更新"
        android:onClick="btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</android.support.constraint.ConstraintLayout>


第二步:在MainActivity.java中去调用就可以了。


public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

    }

    public void btn(View v){
        MyApplication.getServiceUpdateInfo(true);//参数为true,为手动点击检测更新
    }
}



结束语:

好了到这就完成这个功能了,希望这篇博客对大家有用,哪里有写的不好的地方,欠缺的地方。欢迎大家指出来。咱们共同进步。谢谢大家啦,如果这篇文章对你有用。

麻烦点个赞。如果博客中有什么问题欢迎大家留言指出问题。



猜你喜欢

转载自blog.csdn.net/qq_35070105/article/details/71908290