前言:

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

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

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

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

正文:

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

不需要做过多的调整。

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

源码下载:点击打开链接

注意:博主使用的是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";@Overridepublic 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() {@Overridepublic void run() {OkHttpClient mOkHttpClient = new OkHttpClient();Request mRequest = new Request.Builder().url(HttpApi.updateUrl).build();Call mCall = mOkHttpClient.newCall(mRequest);Callback callback = new Callback()  {@Overridepublic void onFailure(Call call, IOException e) {String r = e.toString();Log.d("onFailure",r);}@Overridepublic 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);//创建IntentIntent 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"><ImageViewandroid:id="@+id/download_promp_icon"android:layout_width="wrap_content"android:layout_height="wrap_content" /><LinearLayoutandroid:orientation="vertical"android:layout_marginLeft="10dp"android:layout_width="wrap_content"android:layout_height="wrap_content"><TextViewandroid:id="@+id/download_title"android:layout_width="wrap_content"android:layout_height="wrap_content" /><TextViewandroid: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;//这个是用来是否为手动点击获取更新信息的 默认为falseprivate static boolean isClick = false;//刚刚在App中获取到的信息private static UpdateInfo mUpdateInfo;@Overridepublic 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() {@Overridepublic void onClick(DialogInterface dialog, int which) {dialog.dismiss();}});break;case 1:   //正常升级mDialog.setMessage(mUpdateInfo.getUpgradeinfo());mDialog.setPositiveButton("去升级", new DialogInterface.OnClickListener() {@Overridepublic 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() {@Overridepublic void onClick(DialogInterface dialog, int which) {dialog.dismiss();}});break;case 2:  //强制升级mDialog.setMessage(mUpdateInfo.getUpgradeinfo());mDialog.setPositiveButton("升级", new DialogInterface.OnClickListener() {@Overridepublic 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() {@Overridepublic 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"><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="horizontal"><TextViewandroid:id="@+id/download_notice_name_tv"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_margin="10dp"/><TextViewandroid: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><ProgressBarandroid: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@Overridepublic IBinder onBind(Intent intent) {return null;}@Overridepublic 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{@Overrideprotected 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() {@Overridepublic void onFailure(Call call, IOException e) {downloadResult(DOWNLOAD_FAIL);}@Overridepublic 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   中注册服务的代码

        <!-- 注册服务 --><serviceandroid: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卡有用空间大小,错误返回-1static 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卡的空间大小,错误返码1static 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"><TextViewandroid: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" /><Buttonandroid: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 {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}public void btn(View v){MyApplication.getServiceUpdateInfo(true);//参数为true,为手动点击检测更新}
}

结束语:

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

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

Android 实现通知栏通知APP版本更新相关推荐

  1. android通知栏自定义软件,android实现通知栏下载更新app示例

    1.设计思路,使用VersionCode定义为版本升级参数. android为我们定义版本提供了2个属性: android:versionCode="1" android:vers ...

  2. Android开发-Notification通知栏通知最基础运用

    从 Android 8.0(API 级别 26)开始,所有通知都必须分配到相应的渠道.对于每个渠道,您可以设置应用于其中的所有通知的视觉和听觉行为.然后,用户可以更改这些设置,并确定您应用中的哪些通知 ...

  3. android 禁用通知栏_如何在Android上禁用通知

    android 禁用通知栏 Notifications are great, and Android's notification system is arguably the best out th ...

  4. android反射开启通知_作为Android开发者 你真的知道app从启动到主页显示的过程吗?...

    前言 之前我跟大家说过,在一个夜黑风高的晚上,我的男同事突然给我发了一条微信,我点开来看,他竟然问我Android从按下开机键到启动到底发生了什么?此刻我的内心如下图: 然后就在昨天晚上,我又收到了他 ...

  5. android 通知 广告,解决三星/小米等Android手机通知栏推送广告的问题

    三星和小米都是使用安卓系统的手机,有时候突然在手机通知栏弹出很多的广告,而且广告是不定时的弹出,你把消息清理掉之后,过段时间还是会弹出广告. 而且下载的都是一些乱七八糟的东西,对手机没有什么用处,想完 ...

  6. android pad版本 yy,YY游戏直播app(Android版)1.2.0版本更新

    YY游戏直播app(Android版)1.2.0版本更新 [更新时间] 2014年4月18日 [下载方式] [内容提要] YY游戏直播,上百款热门游戏.最新赛事直播,每天实时热播精彩不停歇! 关注你喜 ...

  7. Android 10.0下拉通知栏 通知列表 添加通知头

    1.概述 在10.0定制化产品开发中,需求要求对SystemUI通知栏ui进行定制,在状态栏展开布局中的通知栏增加通知头文字 2.下拉通知栏 通知列表 添加通知头的核心类 /frameworks/ba ...

  8. 【业务篇】史上最全经验版用例之IOS和Android版APP版本更新、IOS版规避审核?

    一.IOS app设置苹果审核 为了app提交苹果能快速审核通过,故需设置app审核状态,隐藏部分敏感功能 1.线上app版本1.0.0,新版本app2.0.0测试通过,设置2.0.0版本app审核状 ...

  9. android应用内版本更新,Flutter 应用内App版本更新

    一.前言 我们平时开发原生应用时有新版本发布都会有版本升级提示,然后引导客户去下载更新版本,iOS一般的做法是跳转到AppStore更新,Android的处理办法要么是商店更新,要么是应用内直接下载安 ...

最新文章

  1. python中sorted和.sorted 、reversed和reverse的使用
  2. 【项目管理】敏捷小品:Rupert 工业公司 项目:~Alpha~
  3. STM32 USB虚拟串口原理(上)
  4. java企业人事管理系统源码_企业人事管理系统完美版源代码 - 源码下载|行业应用软件|企业管理(财务/ERP/EIP等)|源代码 - 源码中国...
  5. JWT(Json Web Token)介绍
  6. MySQL数据库使某个不是主键的字段唯一
  7. 奥维地图(OMAP)中坐标为什么有偏移?如何基于WGS84或GCJ02的经纬度坐标生成kml?怎么导出图上一个标签点的WGS84经纬度坐标?
  8. 如何查看已删除的微信聊天记录?教你两招,找到答案
  9. 【现代通信原理笔记】8 蜂窝系统
  10. 如何不花钱也能下载17sucai网的网页或者单页
  11. 100%BIM学员的疑惑:不会CAD可以学Revit吗?
  12. 大数据01:前置条件
  13. Latex的中文模板分享~~~
  14. VSCode 基本使用
  15. Project Euler in Java [001-040]
  16. 无忧考吧java的题库准吗,无忧考吧题库_无忧考吧从业题库难度和真正考试难度一样吗_淘题吧...
  17. 阿里云 云盾 安骑士 监控ECS离线 安全组规则 ip设置
  18. Ubuntu下的Rabbitvcs安装配置
  19. 【转】区块链的隐私保护方案介绍
  20. 嵌入式python智能实训总结_智能楼宇实训心得体会

热门文章

  1. IT项目管理中projects、programs和portfolio之间的关系,附带operations以及OPM之间的关系分析
  2. 对抗网易相册不能贴图(解决)
  3. pdf会签_设备验收管理办法20140604(会签签批版).pdf
  4. 大搜车与永达二手车合作,大型汽车经销商加快数字化进程
  5. 北理工计算机2020学硕录取,北京理工大学2020硕士研究生拟录取名单
  6. Direct3D(D3D)简介
  7. 接班人不是克隆出来的:华为再显接班难
  8. win7系统如何关闭不需要的服务器,连接设备平台服务可以禁止吗,win7系统哪些服务可以禁止...
  9. C51单片机程序注释与样例
  10. 考研日语线上笔记(三):初级日语语法总结20课