前言:
我们似乎在做什么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,为手动点击检测更新 } }
结束语:
好了到这就完成这个功能了,希望这篇博客对大家有用,哪里有写的不好的地方,欠缺的地方。欢迎大家指出来。咱们共同进步。谢谢大家啦,如果这篇文章对你有用。
麻烦点个赞。如果博客中有什么问题欢迎大家留言指出问题。