一个公司做两个网站的好处/seo排名优化北京
前言
更新分全量更新和增量更新(参考)。
库
UpdateAppDemo
引
FileDownloader
说明
下载可用系统自带DownloadManager。该类API level 9后出现,已处理下载失败、重新下载等。下载过程交系统负责,不需过多处理。国内某些机型阉割自带DownloadManager时可自实现下载类,也可如上引FileDownloader。
使用
依赖
implementation 'com.liulishuo.filedownloader:library:1.7.5'
权限
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
update
AppDownload
package update;import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Environment;import com.liulishuo.filedownloader.BaseDownloadTask;
import com.liulishuo.filedownloader.FileDownloadListener;
import com.liulishuo.filedownloader.FileDownloader;import util.LogUtils;
import util.ToastUtils;/*** @decs: AppDownload* @date: 2018/8/21 21:09* @version: v 1.0*/
class AppDownload {/*** 地址*/public static String path;/*** 浏览器下载** @param context 上下文* @param url url*/public static void downloadByBrowser(Context context, String url) {Uri uri = Uri.parse(url);Intent intent = new Intent(Intent.ACTION_VIEW, uri);intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);context.startActivity(intent);}/*** 应用内下载** @param context 上下文* @param url url* @param versionName 版本名*/public static void downloadInApp(final Context context, String url, final String versionName) {path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/dfs/update/" + versionName + ".apk";// 注册定制组件FileDownloader.setup(context);// 执行FileDownloader.getImpl().create(url).setPath(path).setListener(new FileDownloadListener() {@Overrideprotected void pending(BaseDownloadTask task, int soFarBytes, int totalBytes) {}@Overrideprotected void connected(BaseDownloadTask task, String etag, boolean isContinue, int soFarBytes, int totalBytes) {}@Overrideprotected void progress(BaseDownloadTask task, int soFarBytes, int totalBytes) {sendBroadcast(context, (int) (soFarBytes * 100.0 / totalBytes), versionName);LogUtils.e((int) (soFarBytes * 100.0 / totalBytes));}@Overrideprotected void blockComplete(BaseDownloadTask task) {}@Overrideprotected void retry(final BaseDownloadTask task, final Throwable ex, final int retryingTimes, final int soFarBytes) {}@Overrideprotected void completed(BaseDownloadTask task) {sendBroadcast(context, 100, versionName);ToastUtils.shortShow("下载完成");}@Overrideprotected void paused(BaseDownloadTask task, int soFarBytes, int totalBytes) {}@Overrideprotected void error(BaseDownloadTask task, Throwable e) {ToastUtils.shortShow("下载出错");}@Overrideprotected void warn(BaseDownloadTask task) {}}).start();}/*** 发送广播** @param context 上下文* @param progress 进度* @param versionName 版本名*/private static void sendBroadcast(Context context, int progress, String versionName) {Intent intent = new Intent("com.self.zsp.dfs.AppUpdate");intent.putExtra("progress", progress);intent.putExtra("title", versionName);context.sendBroadcast(intent);}
}
AppUpdate
package update;import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.text.TextUtils;import util.LogUtils;/*** @decs: AppUpdate* @date: 2018/8/21 21:24* @version: v 1.0*/
public class AppUpdate {public static final int CHECK_BY_VERSION_NAME = 1001;private static final int CHECK_BY_VERSION_CODE = 1002;public static final int DOWNLOAD_BY_APP = 1003;private static final int DOWNLOAD_BY_BROWSER = 1004;private Activity activity;private int checkBy = CHECK_BY_VERSION_CODE;private int downloadBy = DOWNLOAD_BY_APP;private int versionCode = 0;private String apkPath = "";private String versionName = "";/*** 强更否*/private boolean isForce = false;private int localVersionCode = 0;private String localVersionName = "";/*** false不适配7.0(默true)*/public static boolean needFitAndroidN = true;public static boolean showNotification = true;private String updateInfo = "";public AppUpdate fitAndroidN(boolean fitAndroidN) {AppUpdate.needFitAndroidN = fitAndroidN;return this;}private AppUpdate(Activity activity) {this.activity = activity;localVersionInfo(activity);}public static AppUpdate from(Activity activity) {return new AppUpdate(activity);}public AppUpdate checkBy(int checkBy) {this.checkBy = checkBy;return this;}public AppUpdate apkPath(String apkPath) {this.apkPath = apkPath;return this;}public AppUpdate downloadBy(int downloadBy) {this.downloadBy = downloadBy;return this;}public AppUpdate showNotification(boolean showNotification) {AppUpdate.showNotification = showNotification;return this;}public AppUpdate updateInfo(String updateInfo) {this.updateInfo = updateInfo;return this;}public AppUpdate versionCode(int versionCode) {this.versionCode = versionCode;return this;}public AppUpdate versionName(String versionName) {this.versionName = versionName;return this;}public AppUpdate isForce(boolean isForce) {this.isForce = isForce;return this;}/*** 本地版信息** @param context 上下文*/private void localVersionInfo(Context context) {PackageManager manager = context.getPackageManager();try {PackageInfo info = manager.getPackageInfo(context.getPackageName(), 0);// 版本名localVersionName = info.versionName;// 版本号localVersionCode = info.versionCode;} catch (PackageManager.NameNotFoundException e) {e.printStackTrace();}}public void update() {switch (checkBy) {case CHECK_BY_VERSION_CODE:if (versionCode > localVersionCode) {updateExecute();} else {LogUtils.e("当前为最新版" + versionCode + "/" + versionName);}break;case CHECK_BY_VERSION_NAME:if (!versionName.equals(localVersionName)) {updateExecute();} else {LogUtils.e("当前版本最新" + versionCode + "/" + versionName);}break;default:break;}}private void updateExecute() {AppUpdateDialog dialog = new AppUpdateDialog(activity, new Callback() {@Overridepublic void callback(int position) {switch (position) {// cancelcase 0:if (isForce) {System.exit(0);}break;// surecase 1:if (downloadBy == DOWNLOAD_BY_APP) {if (isWifiConnect(activity)) {AppDownload.downloadInApp(activity, apkPath, versionName);} else {new AppUpdateDialog(activity, new Callback() {@Overridepublic void callback(int position) {if (position == 1) {AppDownload.downloadByBrowser(activity, apkPath);} else {if (isForce) {activity.finish();}}}}).setContent("目前手机非WIFI\n继续下载更新吗?").show();}} else if (downloadBy == DOWNLOAD_BY_BROWSER) {AppDownload.downloadByBrowser(activity, apkPath);}break;default:break;}}});String content = "发现新版本" + versionName + "\n下载更新吗?";if (!TextUtils.isEmpty(updateInfo)) {content = "发现新版本" + versionName + "下载更新吗?\n\n" + updateInfo;}dialog.setContent(content);dialog.setCancelable(false);dialog.show();}/*** WIFI连状*/private static boolean isWifiConnect(Context context) {ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);if (cm != null) {NetworkInfo networkInfo = cm.getActiveNetworkInfo();return networkInfo != null && networkInfo.getType() == ConnectivityManager.TYPE_WIFI;}return false;}
}
AppUpdateDialog
package update;import android.annotation.SuppressLint;
import android.app.Dialog;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;import com.self.zsp.dfs.R;/*** @decs: ConfirmDialog* @date: 2018/8/21 21:44* @version: v 1.0*/
public class AppUpdateDialog extends Dialog {private TextView content;private Callback callback;/*** constructor** @param context 上下文* @param callback 回调*/AppUpdateDialog(Context context, Callback callback) {super(context, R.style.AppUpdateDialog);this.callback = callback;setCustomDialog();}private void setCustomDialog() {@SuppressLint("InflateParams") View view = LayoutInflater.from(getContext()).inflate(R.layout.app_update_dialog, null);TextView tvSure = view.findViewById(R.id.tvAppUpdateDialogSure);TextView tvCancel = view.findViewById(R.id.tvAppUpdateDialogCancel);content = view.findViewById(R.id.tvAppUpdateDialogTitle);tvSure.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {callback.callback(1);AppUpdateDialog.this.cancel();}});tvCancel.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {callback.callback(0);AppUpdateDialog.this.cancel();}});super.setContentView(view);}public AppUpdateDialog setContent(String s) {content.setText(s);return this;}
}
AppUpdateReceiver
package update;import android.app.Notification;
import android.app.NotificationManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.support.v4.app.NotificationCompat;
import android.support.v4.content.FileProvider;import java.io.File;
/*** @decs: AppUpdateReceiver* @date: 2018/8/21 21:21* @version: v 1.0*/
public class AppUpdateReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {int notifyId = 1;int progress = intent.getIntExtra("progress", 0);String title = intent.getStringExtra("title");NotificationManager nm = null;if (AppUpdate.showNotification) {NotificationCompat.Builder builder = new NotificationCompat.Builder(context);builder.setContentTitle("正在下载" + title);builder.setSmallIcon(android.R.mipmap.sym_def_app_icon);builder.setProgress(100, progress, false);Notification notification = builder.build();nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);nm.notify(notifyId, notification);}if (progress == 100) {if (nm != null) {nm.cancel(notifyId);}if (AppDownload.path != null) {Intent i = new Intent(Intent.ACTION_VIEW);File file = new File(AppDownload.path);if (AppUpdate.needFitAndroidN && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);Uri contentUri = FileProvider.getUriForFile(context, "com.self.zsp.dfs.fileprovider", file);i.setDataAndType(contentUri, "application/vnd.android.package-archive");} else {i.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");}i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);context.startActivity(i);}}}
}
Callback
package update;/*** @decs: 回调* @date: 2018/8/21 21:15* @version: v 1.0*/
public interface Callback {/*** 回调** @param position 位*/void callback(int position);
}
drawable
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"android:shape="rectangle"><sizeandroid:width="40dp"android:height="20dp" /><solid android:color="#EFEFEF" /><corners android:radius="12dp" />
</shape>
布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="270dp"android:layout_height="wrap_content"android:background="@drawable/app_update_dialog"android:orientation="vertical"><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginLeft="15dp"android:layout_marginRight="15dp"android:layout_marginTop="15dp"android:gravity="center_horizontal"android:text="@string/hint"android:textColor="@color/fontHint"android:textSize="19sp" /><TextViewandroid:id="@+id/tvAppUpdateDialogTitle"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginBottom="10dp"android:layout_marginLeft="15dp"android:layout_marginRight="15dp"android:layout_marginTop="10dp"android:gravity="center_horizontal"android:lineSpacingExtra="5dp"android:textColor="@color/fontInput"android:textSize="17sp" /><Viewandroid:layout_width="match_parent"android:layout_height="1dp"android:layout_marginTop="13dp"android:background="#DFDFDF" /><LinearLayoutandroid:layout_width="match_parent"android:layout_height="44dp"android:orientation="horizontal"><TextViewandroid:id="@+id/tvAppUpdateDialogCancel"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:clickable="true"android:focusable="true"android:gravity="center"android:text="@string/cancel"android:textColor="@color/fontInput"android:textSize="17sp" /><Viewandroid:layout_width="1dp"android:layout_height="match_parent"android:background="#DFDFDF" /><TextViewandroid:id="@+id/tvAppUpdateDialogSure"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:clickable="true"android:focusable="true"android:gravity="center"android:text="@string/sure"android:textColor="@color/fontInput"android:textSize="17sp" /></LinearLayout>
</LinearLayout>
styles
<style name="AppUpdateDialog" parent="@android:style/Theme.Dialog"><item name="android:windowFrame">@null</item><item name="android:windowIsFloating">true</item><item name="android:windowIsTranslucent">false</item><item name="android:windowNoTitle">true</item><item name="android:windowBackground">@drawable/app_update_dialog</item><item name="android:backgroundDimEnabled">true</item>
</style>
主代码
private AppUpdateReceiver appUpdateReceiver;/*** 初始应用更新接收器*/
private void stepAppUpdateReceiver() {IntentFilter intentFilter = new IntentFilter();intentFilter.addAction("com.self.zsp.dfs.AppUpdate");appUpdateReceiver = new AppUpdateReceiver();registerReceiver(appUpdateReceiver, intentFilter);
}AppUpdate.from(this)// 更检方式(默VersionCode).checkBy(AppUpdate.CHECK_BY_VERSION_NAME).versionCode(2).versionName("2.0").apkPath("http://yapkwww.cdn.anzhi.com/data4/apk/201808/09/8e0274d7643e6898fab820bc1cf7eba6_73867900.apk")// 下载进度至通知栏(默true).showNotification(true)// 更日志.updateInfo("测试")// 下载方式(应用内下载、手机浏览器下载。默应用内下载).downloadBy(AppUpdate.DOWNLOAD_BY_APP)// 强更(默false,强更用户不同意不可用).isForce(true).update();@Override
protected void onDestroy() {super.onDestroy(); unregisterReceiver(appUpdateReceiver);
}
注意
- 注意6.0运行时权限、7.0FileProvider。
- 8.0限制静态注册广播,改动态注册。参考
- 通知需适配8.0。