├── .gitignore ├── .travis.yml ├── README.md ├── README_UN.MD ├── README_V1.1.md ├── README_V1.md ├── build.gradle ├── gif ├── AllenVersionChecker.png ├── V2.gif ├── custom.gif ├── main.jpg ├── style1.png ├── style2.png ├── style3.png ├── style4.png ├── v2.jpg └── versionparams.png ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── library.jar ├── library ├── .gitignore ├── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── local.properties ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── allenliu │ │ └── versionchecklib │ │ ├── callback │ │ ├── APKDownloadListener.java │ │ ├── CommitClickListener.java │ │ ├── DialogDismissListener.java │ │ ├── DownloadListener.java │ │ └── OnCancelListener.java │ │ ├── core │ │ ├── JumpActivity.java │ │ ├── VersionFileProvider.java │ │ └── http │ │ │ ├── AllenHttp.java │ │ │ ├── FileCallBack.java │ │ │ ├── HttpHeaders.java │ │ │ ├── HttpParams.java │ │ │ └── HttpRequestMethod.java │ │ ├── utils │ │ ├── ALog.java │ │ ├── AllenEventBusUtil.java │ │ ├── AppUtils.java │ │ └── FileHelper.java │ │ └── v2 │ │ ├── AllenVersionChecker.java │ │ ├── builder │ │ ├── BuilderManager.kt │ │ ├── DownloadBuilder.java │ │ ├── NotificationBuilder.java │ │ ├── RequestVersionBuilder.java │ │ └── UIData.java │ │ ├── callback │ │ ├── CustomDownloadFailedListener.java │ │ ├── CustomDownloadingDialogListener.java │ │ ├── CustomInstallListener.java │ │ ├── CustomVersionDialogListener.java │ │ ├── DownloadListenerKt.kt │ │ ├── ForceUpdateListener.java │ │ ├── LifecycleListener.kt │ │ └── RequestVersionListener.java │ │ ├── eventbus │ │ ├── AllenEventType.java │ │ ├── BaseEvent.java │ │ └── CommonEvent.java │ │ ├── net │ │ ├── DownloadMangerV2.java │ │ └── RequestVersionManager.java │ │ └── ui │ │ ├── AllenBaseActivity.kt │ │ ├── DownloadFailedActivity.kt │ │ ├── DownloadingActivity.kt │ │ ├── NotificationHelper.kt │ │ ├── UIActivity.kt │ │ └── VersionService.kt │ └── res │ ├── drawable │ └── progressbar_horizontal.xml │ ├── layout │ └── downloading_layout.xml │ ├── values-en │ └── strings.xml │ ├── values │ ├── colors.xml │ ├── ids.xml │ ├── strings.xml │ └── styles.xml │ └── xml │ └── versionchecklib_file_paths.xml ├── sample ├── .gitignore ├── 1_1.apk ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── allenliu │ │ └── sample │ │ ├── MainActivity.java │ │ ├── MyApplication.java │ │ ├── v1 │ │ └── BaseDialog.java │ │ └── v2 │ │ └── V2Activity.java │ └── res │ ├── drawable │ ├── custom_bg.png │ └── shape_corner.xml │ ├── layout │ ├── activity_custom_version_dialog.xml │ ├── activity_custom_version_dialog_two.xml │ ├── activity_main.xml │ ├── activity_v1.xml │ ├── activity_v2.xml │ ├── custom.xml │ ├── custom_dialog_one_layout.xml │ ├── custom_dialog_two_layout.xml │ ├── custom_download_failed_dialog.xml │ └── custom_download_layout.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ ├── dialog1.jpg │ ├── dialog2.jpg │ ├── dialog3.jpg │ ├── dialog4.jpg │ ├── dialog5.jpg │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── mipmap-xxxhdpi │ └── ic_launcher.png │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | 5 | .DS_Store 6 | /build 7 | /captures 8 | .externalNativeBuild 9 | .idea 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: android 2 | android: 3 | components: 4 | - tools 5 | - build-tools-24.0.2 6 | - android-24 7 | - extra-android-m2repository 8 | - extra-android-support 9 | before_install: 10 | - chmod +x gradlew 11 | script: 12 | - "./gradlew assembleRelease" 13 | -------------------------------------------------------------------------------- /README_UN.MD: -------------------------------------------------------------------------------- 1 | ## CheckVersionLib[![](https://jitpack.io/v/AlexLiuSheng/CheckVersionLib.svg)](https://jitpack.io/#AlexLiuSheng/CheckVersionLib) 2 | ## V2版震撼来袭,功能强大,链式编程,调用简单,集成轻松,扩展性强大 3 | 4 | 老规矩先看V2效果,这个版本最大的特点就是使用非常简单,相对于1.+版本 5 | 6 | ### 效果 7 | 8 | 9 | ### 特点 10 | - [x] 任何地方都可以调用 11 | 12 | - [x] **简单简单简单简单**(重要的话我说四遍) 13 | 14 | - [x] **扩展性强大** 15 | 16 | - [x] 所有具有升级功能的app均可使用,耶稣说的 17 | 18 | - [x] **更强大的自定义界面支持** 19 | 20 | - [x] 支持强制更新(一行代码) 21 | 22 | - [x] 支持静默下载 (一行代码) 23 | 24 | - [x] 适配到Android 13 25 | 26 | ### 导入 27 | ``` 28 | allprojects { 29 | repositories { 30 | ... 31 | maven { url 'https://jitpack.io' } 32 | } 33 | } 34 | ``` 35 | 36 | ``` 37 | dependencies { 38 | implementation 'com.github.AlexLiuSheng:CheckVersionLib:2.4.2' 39 | } 40 | ``` 41 | 42 | ### 使用 43 | 44 | 两种模式 45 | 46 | > 只使用下载模式 47 | 48 | 先来个最简单的调用 49 | 50 | ``` 51 | AllenVersionChecker 52 | .getInstance() 53 | .downloadOnly( 54 | UIData.create().setDownloadUrl(downloadUrl) 55 | ) 56 | .executeMission(context); 57 | ``` 58 | 59 | `UIData`:UIData是一个Bundle,用于存放用于UI展示的一些数据,后面自定义界面时候可以拿来用 60 | 61 | 62 | 63 | > 请求服务器版本+下载 64 | 65 | 该模式最简单的使用 66 | ``` 67 | AllenVersionChecker 68 | .getInstance() 69 | .requestVersion() 70 | .setRequestUrl(requestUrl) 71 | .request(new RequestVersionListener() { 72 | @Nullable 73 | @Override 74 | public UIData onRequestVersionSuccess(String result) { 75 | //拿到服务器返回的数据,解析,拿到downloadUrl和一些其他的UI数据 76 | ... 77 | //如果是最新版本直接return null 78 | return UIData.create().setDownloadUrl(downloadUrl); 79 | } 80 | 81 | @Override 82 | public void onRequestVersionFailure(String message) { 83 | 84 | } 85 | }) 86 | .executeMission(context); 87 | 88 | 89 | ``` 90 | 请求版本一些其他的http参数可以设置,如下 91 | 92 | ``` 93 | AllenVersionChecker 94 | .getInstance() 95 | .requestVersion() 96 | .setHttpHeaders(httpHeader) 97 | .setRequestMethod(HttpRequestMethod.POSTJSON) 98 | .setRequestParams(httpParam) 99 | .setRequestUrl(requestUrl) 100 | .request(new RequestVersionListener() { 101 | @Nullable 102 | @Override 103 | public UIData onRequestVersionSuccess(String result) { 104 | //拿到服务器返回的数据,解析,拿到downloadUrl和一些其他的UI数据 105 | ... 106 | UIData uiData = UIData 107 | .create() 108 | .setDownloadUrl(downloadUrl) 109 | .setTitle(updateTitle) 110 | .setContent(updateContent); 111 | //放一些其他的UI参数,拿到后面自定义界面使用 112 | uiData.getVersionBundle().putString("key", "your value"); 113 | return uiData; 114 | 115 | } 116 | 117 | @Override 118 | public void onRequestVersionFailure(String message) { 119 | 120 | } 121 | }) 122 | .executeMission(context); 123 | ``` 124 | 125 | ### 合适的地方关闭任务 126 | 为了避免不必要的内存泄漏,需要在合适的地方取消任务 127 | ``` 128 | AllenVersionChecker.getInstance().cancelAllMission(); 129 | ``` 130 | 131 | 132 | 以上就是最基本的使用(库默认会有一套界面),如果还不满足项目需求,下面就可以用这个库来飙车了 133 | 134 | ### 一些其他的function设置 135 | 解释下,下面的builder叫`DownloadBuilder` 136 | ``` 137 | DownloadBuilder builder=AllenVersionChecker 138 | .getInstance() 139 | .downloadOnly(); 140 | 141 | 142 | or 143 | 144 | 145 | 146 | DownloadBuilder builder=AllenVersionChecker 147 | .getInstance() 148 | .requestVersion() 149 | .request() 150 | ``` 151 | > 取消任务 152 | 153 | ``` 154 | AllenVersionChecker.getInstance().cancelAllMission(this); 155 | 156 | ``` 157 | > 静默下载 158 | 159 | ``` 160 | builder.setSilentDownload(true); 默认false 161 | ``` 162 | > 设置当前服务器最新的版本号,供库判断是否使用缓存 163 | 164 | - 缓存策略:如果本地有安装包,首先判断与当前运行的程序的versionCode是否不一致,然后判断是否有传入最新的 165 | versionCode,如果传入的versionCode大于本地的,重新从服务器下载,否则使用缓存 166 | 167 | ``` 168 | builder.setNewestVersionCode(int); 默认null 169 | ``` 170 | > 强制更新 171 | 172 | 设置此listener即代表需要强制更新,会在用户想要取消下载的时候回调 173 | 需要你自己关闭所有界面 174 | ``` 175 | builder.setForceUpdateListener(() -> { 176 | forceUpdate(); 177 | }); 178 | ``` 179 | **update in v2.2.1** 180 | 动态设置是否强制更新,如果使用本库来请求服务器,可以在回调时动态设置一些参数或者回调 181 | ``` 182 | public UIData onRequestVersionSuccess(DownloadBuilder downloadBuilder,String result) { 183 | downloadBuilder.setForceUpdateListener(() -> { 184 | forceUpdate(); 185 | }); 186 | Toast.makeText(V2Activity.this, "request successful", Toast.LENGTH_SHORT).show(); 187 | return crateUIData(); 188 | } 189 | ``` 190 | > 下载忽略本地缓存 191 | 192 | 如果本地有安装包缓存也会重新下载apk 193 | 194 | ``` 195 | builder.setForceRedownload(true); 默认false 196 | ``` 197 | 198 | > 是否显示下载对话框 199 | ``` 200 | builder.setShowDownloadingDialog(false); 默认true 201 | ``` 202 | > 是否显示通知栏 203 | ``` 204 | builder.setShowNotification(false); 默认true 205 | ``` 206 | > **以前台service运行(update in 2.2.2)** 207 | 推荐以前台服务运行更新,防止在后台时,服务被杀死 208 | ``` 209 | builder.setRunOnForegroundService(true); 默认true 210 | 211 | ``` 212 | > 自定义通知栏 213 | ``` 214 | builder.setNotificationBuilder( 215 | NotificationBuilder.create() 216 | .setRingtone(true) 217 | .setIcon(R.mipmap.dialog4) 218 | .setTicker("custom_ticker") 219 | .setContentTitle("custom title") 220 | .setContentText(getString(R.string.custom_content_text)) 221 | ); 222 | ``` 223 | > 是否显示失败对话框 224 | 225 | ``` 226 | builder.setShowDownloadFailDialog(false); 默认true 227 | ``` 228 | > 自定义下载路径 229 | 230 | ``` 231 | builder.setDownloadAPKPath(address); 默认:/storage/emulated/0/AllenVersionPath/ 232 | ``` 233 | > 自定义下载文件名 234 | ``` 235 | builder.setApkName(apkName); 默认:getPackageName() 236 | ``` 237 | > 可以设置下载监听 238 | 239 | ``` 240 | builder.setApkDownloadListener(new APKDownloadListener() { 241 | @Override 242 | public void onDownloading(int progress) { 243 | 244 | } 245 | 246 | @Override 247 | public void onDownloadSuccess(File file) { 248 | 249 | } 250 | 251 | @Override 252 | public void onDownloadFail() { 253 | 254 | } 255 | }); 256 | ``` 257 | > 设置取消监听 258 | 此回调会监听所有cancel事件 259 | ``` 260 | 261 | builder.setOnCancelListener(() -> { 262 | Toast.makeText(V2Activity.this,"Cancel Hanlde",Toast.LENGTH_SHORT).show(); 263 | }); 264 | ``` 265 | **如果想单独监听几种状态下的cancel,可像如下这样设置** 266 | - ` builder.setDownloadingCancelListener();` 267 | - `builder.setDownloadFailedCancelListener();` 268 | - `builder.setReadyDownloadCancelListener();` 269 | 270 | > 设置确定监听(**added after 2.2.2**) 271 | 272 | - ` builder.setReadyDownloadCommitClickListener();` 273 | - `builder.setDownloadFailedCommitClickListener();` 274 | 275 | > 静默下载+直接安装(不会弹出升级对话框) 276 | ``` 277 | builder.setDirectDownload(true); 278 | builder.setShowNotification(false); 279 | builder.setShowDownloadingDialog(false); 280 | builder.setShowDownloadFailDialog(false); 281 | ``` 282 | > 自定义安装回调 283 | ``` 284 | setCustomDownloadInstallListener(CustomInstallListener customDownloadInstallListener) 285 | ``` 286 | 287 | ### 自定义界面 288 | 289 | 自定义界面使用回调方式,开发者需要返回自己定义的Dialog(父类android.app) 290 | 291 | - 所有自定义的界面必须使用listener里面的context实例化 292 | 293 | - 界面展示的数据通过UIData拿 294 | 295 | > **自定义显示更新界面** 296 | 297 | 设置`CustomVersionDialogListener` 298 | 299 | 300 | - 定义此界面**必须**有一个确定下载的按钮,按钮id必须为`@id/versionchecklib_version_dialog_commit` 301 | 302 | - 如果有取消按钮(没有忽略本条要求),则按钮id必须为`@id/versionchecklib_version_dialog_cancel` 303 | 304 | eg. 305 | 306 | ``` 307 | builder.setCustomVersionDialogListener((context, versionBundle) -> { 308 | BaseDialog baseDialog = new BaseDialog(context, R.style.BaseDialog, R.layout.custom_dialog_one_layout); 309 | //versionBundle 就是UIData,之前开发者传入的,在这里可以拿出UI数据并展示 310 | TextView textView = baseDialog.findViewById(R.id.tv_msg); 311 | textView.setText(versionBundle.getContent()); 312 | return baseDialog; 313 | }); 314 | 315 | ``` 316 | 317 | > **自定义下载中对话框界面** 318 | 319 | 设置`CustomDownloadingDialogListener` 320 | 321 | 322 | - 如果此界面要设计取消操作(没有忽略),请务必将id设置为`@id/versionchecklib_loading_dialog_cancel` 323 | 324 | 325 | ``` 326 | builder.setCustomDownloadingDialogListener(new CustomDownloadingDialogListener() { 327 | @Override 328 | public Dialog getCustomDownloadingDialog(Context context, int progress, UIData versionBundle) { 329 | BaseDialog baseDialog = new BaseDialog(context, R.style.BaseDialog, R.layout.custom_download_layout); 330 | return baseDialog; 331 | } 332 | //下载中会不断回调updateUI方法 333 | @Override 334 | public void updateUI(Dialog dialog, int progress, UIData versionBundle) { 335 | TextView tvProgress = dialog.findViewById(R.id.tv_progress); 336 | ProgressBar progressBar = dialog.findViewById(R.id.pb); 337 | progressBar.setProgress(progress); 338 | tvProgress.setText(getString(R.string.versionchecklib_progress, progress)); 339 | } 340 | }); 341 | ``` 342 | 343 | > **自定义下载失败对话框** 344 | 345 | 设置CustomDownloadFailedListener 346 | 347 | - 如果有**重试**按钮请将id设置为`@id/versionchecklib_failed_dialog_retry` 348 | 349 | - 如果有 **确认/取消**按钮请将id设置为`@id/versionchecklib_failed_dialog_cancel` 350 | 351 | ``` 352 | builder.setCustomDownloadFailedListener((context, versionBundle) -> { 353 | BaseDialog baseDialog = new BaseDialog(context, R.style.BaseDialog, R.layout.custom_download_failed_dialog); 354 | return baseDialog; 355 | }); 356 | ``` 357 | *** 358 | 359 | ### update Log 360 | - 2.2.1 361 | - 修复内存泄漏问题 362 | - 使用binder传递参数 363 | - 一些已知的bug 364 | 365 | 366 | ### 混淆配置 367 | ``` 368 | -keepattributes *Annotation* 369 | -keepclassmembers class * { 370 | @org.greenrobot.eventbus.Subscribe ; 371 | } 372 | -keep enum org.greenrobot.eventbus.ThreadMode { *; } 373 | 374 | # Only required if you use AsyncExecutor 375 | -keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent { 376 | (java.lang.Throwable); 377 | } 378 | ``` 379 | 380 | 381 | ### 最后 382 | 383 | *** 384 | 385 | - 更全面的使用请看 [demo](https://github.com/AlexLiuSheng/CheckVersionLib/blob/master/sample/src/main/java/com/allenliu/sample/v2/V2Activity.java) 386 | 387 | - 感谢各位对本库的支持 388 | 389 | - 欢迎star/issue 390 | 391 | 392 | 393 | ### License 394 | 395 | *** 396 | 397 | Apache 2.0 398 | -------------------------------------------------------------------------------- /README_V1.1.md: -------------------------------------------------------------------------------- 1 | # CheckVersionLib[ ![Download](https://api.bintray.com/packages/zkxy/maven/VersionCheckLib/images/download.svg) ](https://bintray.com/zkxy/maven/VersionCheckLib/_latestVersion) 2 | 现在热更新技术挺火的,大公司都出了自己的热更新框架,但是各家热更新都有各自优缺点,终究不能解决所有bug,万不得已还是得进行版本升级,这是一个android上的自动版本检测并更新库。库集成了检测版本、下载版本以及自动安装升级 3 | ## 特点 4 | - [x] 任何地方都可以检测(可设置定时检测) 5 | 6 | - [x] app内任何地方都可以弹出升级对话框 7 | 8 | - [x] **自定义性强,手动回调解析,适用于各种版本检测接口** 9 | 10 | - [x] 自动处理下载和安装 11 | 12 | - [x] 自动请求读写权限 13 | 14 | - [x] **支持自定义界面** 15 | 16 | - [x] 支持强制更新 17 | 18 | ## 效果 19 | 20 | 21 | 22 | 23 | 24 | ## 使用步骤 25 | ### android studio导入 26 | `compile 'com.allenliu.versionchecklib:library:1.1'` 27 | 28 | 29 | ### 如何使用 30 | 1.自定义service,service继承 `AVersionService `,实现其中的 `onResponses(AVersionService service, String response)`抽象方法. 31 | 32 | 该方法主要是请求版本接口的回调,由于不同的使用者版本检测接口返回数据类型不一致,所以你需要自己解析数据,判断版本号之后调用升级对话框,如果使用库默认的界面直接调用如下方法: `service.showVersionDialog(downloadUrl,title,updateMsg )` 33 | 34 | 示例代码: 35 |           36 | 37 | if (serverVersion > clientVersion) {  38 | //传入下载地址,以及版本更新消息 39 | service.showVersionDialog(downloadUrl,title,updateMsg );} 40 | 41 | 42 | 43 | 44 | 45 | 2.在任意地方开启自定义service,并传入`VersionParam` 46 | 47 | versionParams = new VersionParams().setRequestUrl("http://www.baidu.com"); 48 | Intent intent = new Intent(this, DemoService.class); 49 | intent.putExtra(AVersionService.VERSION_PARAMS_KEY, versionParams); 50 | startService(intent); 51 | 52 | `VersionParams`有如下方法,除了requestUrl都是可选值 53 | 54 | 55 | 56 | ### **自定义界面** 57 | 如果想自定义界面,只需创建一个继承自`VersionDialogActivity`的Activity,Activity设置Theme为透明: 58 | 59 | ` android:theme="@style/versionCheckLibvtransparentTheme"` 60 | 61 | 开启Service的时候,将自定义的Activity传入VersionParams 62 | 63 | `setCustomDownloadActivityClass(CustomVersionDialogActivity.class)` 64 | 65 | - 自定义 版本dialog,重写 `showVersionDialog()` ,在里面实现自己的逻辑,最后调用`downloadFile(url)`或者`downloadFile(url,filecallback)`注意不要调用父类的方法 66 | 67 | - 自定义 下载中dialog,重写`showLoadingDialog(int currentProgress)`,在里面实现自己的逻辑 68 | 69 | - 自定义 下载失败dialog ,重写`showFailDialog`,实现自己的逻辑 70 | 71 | - 强制更新。如果使用默认的版本dialog,`setCancelClickListner`回调里实现,具体用法请看demo 72 | 73 | - 除此之外还可以在定义的Activity里面监听一些下载和点击回调 74 | 75 | setOnDownloadSuccessListener(this); 76 | 77 | setCommitClickListener(this); 78 | 79 | setCancelClickListener(this); 80 | 81 | setOnDownloadingListener(this); 82 | 83 | ### 下载通知栏图标和文字替换 84 | 需要自定义图标只需在mimap文件下建立`ic_launcher`图标,替换标题只需在项目xml定义`app_name`属性,还有其他一些属性替换,如下表: 85 | 86 | | 属性名 | 属性值 | 87 | | ------------- |:-------------:| 88 | | versionchecklib_confirm | 确认 | 89 | | versionchecklib_cancel | 取消 | 90 | |versionchecklib_retry | 重试 | 91 | |versionchecklib_download_fail_retry| 下载失败是否重试? | 92 | |versionchecklib_download_finish | 下载完成,点击安装 | 93 | |versionchecklib_downloading | 正在下载中... | 94 | |versionchecklib_check_new_version |检测到新版本 | 95 | |versionchecklib_download_fail | 下载失败,点击重试|   96 | 更详细的使用请看demo 97 | `欢迎star和提issue` 98 | ## License 99 | 100 | Copyright 2017 AllenLiu. 101 | 102 | Licensed to the Apache Software Foundation (ASF) under one or more contributor 103 | license agreements. See the NOTICE file distributed with this work for 104 | additional information regarding copyright ownership. The ASF licenses this 105 | file to you under the Apache License, Version 2.0 (the "License"); you may not 106 | use this file except in compliance with the License. You may obtain a copy of 107 | the License at 108 | 109 | http://www.apache.org/licenses/LICENSE-2.0 110 | 111 | Unless required by applicable law or agreed to in writing, software 112 | distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 113 | WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 114 | License for the specific language governing permissions and limitations under 115 | the License. 116 | 117 | -------------------------------------------------------------------------------- /README_V1.md: -------------------------------------------------------------------------------- 1 | # CheckVersionLib[ ![Download](https://api.bintray.com/packages/zkxy/maven/VersionCheckLib/images/download.svg) ](https://bintray.com/zkxy/maven/VersionCheckLib/_latestVersion) 2 | 3 | # [V2版来袭](https://github.com/AlexLiuSheng/CheckVersionLib/blob/master/README.MD) 4 | [English Doc](https://github.com/AlexLiuSheng/CheckVersionLib/blob/master/README_EN.md) 5 | ## 特点 6 | - [x] 任何地方都可以检测(可设置定时检测) 7 | 8 | - [x] app内任何地方都可以弹出升级对话框 9 | 10 | - [x] **自定义性强,手动回调解析,适用于各种版本检测接口** 11 | 12 | - [x] 自动处理下载和安装 13 | 14 | - [x] 自动请求读写权限 15 | 16 | - [x] **支持自定义界面** 17 | 18 | - [x] 支持强制更新 19 | 20 | - [x] 支持静默下载 21 | 22 | - [x] 使用okhttp请求,不与第三方请求框架冲突 23 | 24 | - [x] 适配到Android O 25 | 26 | ## 效果 27 | 28 | 29 | 30 | 31 | 32 | ## 使用步骤 33 | ### android studio导入 34 | `compile 'com.allenliu.versionchecklib:library:1.8.8'` 35 | 36 | 37 | ### 如何使用 38 | #### 1.请求版本接口 + 下载模块 39 | 1.自定义service,service继承 `AVersionService `,实现其中的 `onResponses(AVersionService service, String response)`抽象方法. 40 | 41 | 该方法主要是请求版本接口的回调,由于不同的使用者版本检测接口返回数据类型不一致,所以你需要自己解析数据,判断版本号之后调用升级对话框,如果使用库默认的界面直接调用如下方法: `service.showVersionDialog(downloadUrl,title,updateMsg )` 42 | 43 | 示例代码: 44 |           45 | 46 | if (serverVersion > clientVersion) {  47 | //传入下载地址,以及版本更新消息 48 | service.showVersionDialog(downloadUrl,title,updateMsg ); 49 | // or 50 | service.showVersionDialog(downloadUrl,title,updateMsg,bundle); 51 | } 52 | 53 | 54 | 55 | 56 | 2.在任意地方开启自定义service,并传入`VersionParam` 57 | 58 | ``` 59 | VersionParams.Builder builder = new VersionParams.Builder() 60 | .setRequestUrl("http://www.baidu.com") 61 | .setService(DemoService.class); 62 | 63 | AllenChecker.startVersionCheck(this, builder.build()); 64 | ``` 65 | 66 | #### 2.只使用下载模块 67 | 68 | 69 |    只使用下载模块不用定义第一步的service,正常传入versiongParams参数,不设置requestUrl和service,只用设置onlyDownload 为true。并且传入downloadUrl和需要显示的信息 70 | 71 | 72 | ``` 73 | //如果仅使用下载功能,downloadUrl是必须的 74 | builder.setOnlyDownload(true) 75 | .setDownloadUrl("http://down1.uc.cn/down2/zxl107821.uc/miaokun1/UCBrowser_V11.5.8.945_android_pf145_bi800_(Build170627172528).apk") 76 | .setTitle("检测到新版本") 77 | .setUpdateMsg(getString(R.string.updatecontent)); 78 | 79 | AllenChecker.startVersionCheck(this, builder.build()); 80 | ``` 81 | 82 | `VersionParams`属性见下表: 83 | 84 | | 属性名 | 是否必须 | 默认值 |解释| 85 | | ------------- |:-------------|:-------------|:-------------:| 86 | | requestUrl | 是 |-|请求版本接口的url| 87 | | service | 是 |-|指定你自己的service| 88 | |downloadAPKPath|否|/storage/emulated/0/AllenVersionPath/|apk下载路径| 89 | | httpHeaders | 否 |不传为空|http版本请求header| 90 | | pauseRequestTime | 否 |1000*30|版本接口请求失败与下次请求间隔时间(如果为-1表示请求失败不继续请求)| 91 | | httpHeaders | 否 |不传为空|http版本请求header| 92 | | requestMethod | 否 |GET|http版本请求方式| 93 | | requestParams | 否 |不传为空|http版本请求携带的参数| 94 | | customDownloadActivityClass | 否 |VersionDialogActivity.class|版本dialog Activity,使用默认界面不指定| 95 | | isForceRedownload | 否 |false|如果本地有缓存,是否强制重新下载apk(设置false会如果下载了安装包而用户没有安装则不会再次下载)| 96 | | isSilentDownload | 否 |false|静默下载开关| 97 | | onlyDownload |否|false|是否只使用下载模块| 98 | |title|否|null|只使用下载模块时,升级对话框的title| 99 | |updateMsg|否|null|只使用下载模块时,升级对话框内容| 100 | |downloadUrl|只使用下载模式时必须|-|只使用下载模块时传入的下载apk地址| 101 | |paramBundle|否|null|额外的一些参数可以放里面,可以在versiongDialogActivity里面使用| 102 | |isShowDownloadingDialog|否|true|是否显示下载对话框| 103 | |isShowNotification|否|true|是否显示下载的通知栏| 104 | |isShowDownloadFailDialog|否|true|是否显示下载失败对话框| 105 | 106 | #### 3.开启和关闭log 107 | 108 | `AllenChecker.init(true)` 109 | 110 | #### 4.取消请求 111 | 112 | 取消全部请求 113 | 114 | `AllenChecker.cancelMission();` 115 | 116 | ### **自定义界面** 117 | 如果想自定义界面,只需创建一个继承自`VersionDialogActivity`的Activity, 118 | Activity设置Theme为透明: 119 | 120 | ` android:theme="@style/versionCheckLibvtransparentTheme"` 121 | 122 | 设置launchMode为SingleTask 123 | 124 | ` android:launchMode="singleTask"` 125 | 126 | 记住将自定义的Activity传入VersionParams 127 | 128 | `setCustomDownloadActivityClass(CustomVersionDialogActivity.class)` 129 | 130 | - 调用父类`getVersionTitle()` ,`getVersionUpdateMsg()`,`getVersionParamBundle()`方法,这是从service传过来的值,可以在自定义界面使用 131 | 132 | - 自定义 `versionDialog`: 133 |     重写 `showVersionDialog()` ,在里面实现自己的逻辑,在确认按钮里调用 `super.dealAPK();` 134 | 135 | 136 |     example code: 137 | ``` 138 | versionDialog = new BaseDialog(this, R.style.BaseDialog, R.layout.custom_dialog_two_layout); 139 | TextView tvTitle = (TextView) versionDialog.findViewById(R.id.tv_title); 140 | TextView tvMsg = (TextView) versionDialog.findViewById(R.id.tv_msg); 141 | Button btnUpdate = (Button) versionDialog.findViewById(R.id.btn_update); 142 | 143 | versionDialog.show(); 144 | //设置dismiss listener 用于强制更新,dimiss会回调dialogDismiss方法 145 | versionDialog.setOnDismissListener(this); 146 | //可以使用之前从service传过来的一些参数比如:title。msg,downloadurl,parambundle 147 | tvTitle.setText(getVersionTitle()); 148 | tvMsg.setText(getVersionUpdateMsg()); 149 | //可以使用之前service传过来的值 150 | Bundle bundle = getVersionParamBundle(); 151 | btnUpdate.setOnClickListener(new View.OnClickListener() { 152 | @Override 153 | public void onClick(View view) { 154 | versionDialog.dismiss(); 155 | CustomVersionDialogActivity.super.dealAPK(); 156 | 157 | } 158 | }); 159 | versionDialog.show(); 160 | ``` 161 | 162 | - 自定义 `downloadingDialog`,重写`showLoadingDialog(int currentProgress)`,在里面实现自己的逻辑 163 | 164 | - 自定义 `failDialog` ,重写`showFailDialog`,实现自己的逻辑 165 | 166 | - 强制更新。如果使用默认的版本dialog,`dialogDismiss`和`onDownloadSuccess`回调里关闭app,具体用法请看demo 167 | 168 | - 除此之外还可以在定义的Activity里面监听一些下载和点击回调 169 | 170 | 171 | setApkDownloadListener(this); 172 | setCommitClickListener(this); 173 | setDialogDimissListener(this); 174 | 175 | ### 强制更新 176 | 177 | 主要思路就是监听 178 | 179 | ``` 180 | setApkDownloadListener(this); 181 | setDialogDimissListener(this); 182 | ``` 183 | 184 | 185 | 具体查看[ForceUpdate](https://github.com/AlexLiuSheng/CheckVersionLib/tree/master/ForceUpdateDemo) 186 | 187 | ### 下载通知栏图标和文字替换 188 | 需要自定义图标只需在mimap文件下建立`ic_launcher`图标,替换标题只需在项目xml定义`app_name`属性,还有其他一些属性替换([仍然被替换?](https://github.com/AlexLiuSheng/CheckVersionLib/issues/83)),如下表: 189 | 190 | | 属性名 | 属性值 | 191 | | ------------- |:-------------:| 192 | | versionchecklib_confirm | 确认 | 193 | | versionchecklib_cancel | 取消 | 194 | |versionchecklib_retry | 重试 | 195 | |versionchecklib_download_fail_retry| 下载失败是否重试? | 196 | |versionchecklib_download_finish | 下载完成,点击安装 | 197 | |versionchecklib_downloading | 正在下载中... | 198 | |versionchecklib_check_new_version |检测到新版本 | 199 | |versionchecklib_download_fail | 下载失败,点击重试|   200 | 更详细的使用请看demo 201 | `欢迎star和提issue` 202 | ## 更新日志 203 | V 1.8.8 204 | 205 | - fix the oom of static context 206 | 207 | V 1.8.6 208 | 209 | - fix [issue80](https://github.com/AlexLiuSheng/CheckVersionLib/issues/80) 210 | 211 | V 1.8.4 212 | - support android 8 213 | 214 | V 1.8.3 215 | - fix [issue73](https://github.com/AlexLiuSheng/CheckVersionLib/issues/73) 216 | - fix [issue75](https://github.com/AlexLiuSheng/CheckVersionLib/issues/75) 217 | 218 | V 1.8.2 219 | - fix bug of silent downloading 220 | 221 | V 1.8.0 222 | - fix bugs of force update 223 | - fix [issue](https://github.com/AlexLiuSheng/CheckVersionLib/issues/68) 224 | - V1.7.7 225 | - fix [issue](https://github.com/AlexLiuSheng/CheckVersionLib/issues/64) 226 | - fix re downloading apk when app have cache of apk 227 | - fix [issue](https://github.com/AlexLiuSheng/CheckVersionLib/issues/63) 228 | - V1.7.6 229 | - support cancel all the task 230 | - V1.7.5 231 | - support multiple language mode 232 | - V1.7.4 233 | - solve [issues#59](https://github.com/AlexLiuSheng/CheckVersionLib/issues/59) 234 | - V1.7.2 235 | - support https request 236 | - V1.7.1 237 | - 增加是否显示下载通知栏开关 238 | - 增加是否显示下载对话框开关 239 | - V1.6.9 240 | - VersionDialogActivity statusbar transparent 241 | - V1.6.8 242 | - 增加只使用下载功能用法 243 | - V1.6.6 244 | - 解决[issues#33](https://github.com/AlexLiuSheng/CheckVersionLib/issues/33) 245 | - V1.6.5 246 | - 解决了[issues#32](https://github.com/AlexLiuSheng/CheckVersionLib/issues/32) 247 | - V1.6.0 248 | - 优化项目,移除okgo 249 | - 使用okhttp实现请求和下载 250 | - V1.5.4 [issues#27](https://github.com/AlexLiuSheng/CheckVersionLib/issues/27) 251 | - 解决了 [issues#27](https://github.com/AlexLiuSheng/CheckVersionLib/issues/27) 252 | - V1.5.3 [issues#26](https://github.com/AlexLiuSheng/CheckVersionLib/issues/26) 253 | - 解决了 [issues#26](https://github.com/AlexLiuSheng/CheckVersionLib/issues/26) 254 | - V1.5.2 255 | - 解决了 [issues#25](https://github.com/AlexLiuSheng/CheckVersionLib/issues/25) 256 | - V1.5.1 257 | - solve [issues#24](https://github.com/AlexLiuSheng/CheckVersionLib/issues/24) 258 | - V1.5 259 | - 增加getVersionTitle,getVersionParamBundle,getVersionUpdateMsg方法,方便自定义界面使用 260 | - 修复了对本地缓存apk的判断优化。只有本地安装包与当前app的包名一样并且versioncode不一样才会认为本地有apk 261 | - V1.4 262 | - 修复了之前自定义界面不能使用从service传过去的title,updateMsg问题 263 | - V1.3 264 | - 增加**静默下载**功能 265 | - 优化库启动方式 266 | - V1.2 267 | - **强制重新下载开关**功能 268 | - V1.1 269 | - 添加apk下载缓存,下载完成之后默认不再次下载。安装之后删除安装包 270 | 271 | 272 | ## License 273 | 274 | Copyright 2017 AllenLiu. 275 | 276 | Licensed to the Apache Software Foundation (ASF) under one or more contributor 277 | license agreements. See the NOTICE file distributed with this work for 278 | additional information regarding copyright ownership. The ASF licenses this 279 | file to you under the Apache License, Version 2.0 (the "License"); you may not 280 | use this file except in compliance with the License. You may obtain a copy of 281 | the License at 282 | 283 | http://www.apache.org/licenses/LICENSE-2.0 284 | 285 | Unless required by applicable law or agreed to in writing, software 286 | distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 287 | WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 288 | License for the specific language governing permissions and limitations under 289 | the License. 290 | 291 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | ext.kotlin_version = "1.8.0" 5 | 6 | repositories { 7 | mavenCentral() 8 | maven { url "https://jitpack.io" } 9 | google() 10 | 11 | } 12 | dependencies { 13 | classpath 'com.android.tools.build:gradle:8.0.2' 14 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 15 | 16 | } 17 | } 18 | 19 | allprojects { 20 | repositories { 21 | mavenCentral() 22 | maven { url "https://jitpack.io" } 23 | google() 24 | 25 | } 26 | } 27 | 28 | task clean(type: Delete) { 29 | delete rootProject.buildDir 30 | } 31 | -------------------------------------------------------------------------------- /gif/AllenVersionChecker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexLiuSheng/CheckVersionLib/23ab03936b0bbd78c447ef8d4d10bfba4243e4cf/gif/AllenVersionChecker.png -------------------------------------------------------------------------------- /gif/V2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexLiuSheng/CheckVersionLib/23ab03936b0bbd78c447ef8d4d10bfba4243e4cf/gif/V2.gif -------------------------------------------------------------------------------- /gif/custom.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexLiuSheng/CheckVersionLib/23ab03936b0bbd78c447ef8d4d10bfba4243e4cf/gif/custom.gif -------------------------------------------------------------------------------- /gif/main.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexLiuSheng/CheckVersionLib/23ab03936b0bbd78c447ef8d4d10bfba4243e4cf/gif/main.jpg -------------------------------------------------------------------------------- /gif/style1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexLiuSheng/CheckVersionLib/23ab03936b0bbd78c447ef8d4d10bfba4243e4cf/gif/style1.png -------------------------------------------------------------------------------- /gif/style2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexLiuSheng/CheckVersionLib/23ab03936b0bbd78c447ef8d4d10bfba4243e4cf/gif/style2.png -------------------------------------------------------------------------------- /gif/style3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexLiuSheng/CheckVersionLib/23ab03936b0bbd78c447ef8d4d10bfba4243e4cf/gif/style3.png -------------------------------------------------------------------------------- /gif/style4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexLiuSheng/CheckVersionLib/23ab03936b0bbd78c447ef8d4d10bfba4243e4cf/gif/style4.png -------------------------------------------------------------------------------- /gif/v2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexLiuSheng/CheckVersionLib/23ab03936b0bbd78c447ef8d4d10bfba4243e4cf/gif/v2.jpg -------------------------------------------------------------------------------- /gif/versionparams.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexLiuSheng/CheckVersionLib/23ab03936b0bbd78c447ef8d4d10bfba4243e4cf/gif/versionparams.png -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | ## Project-wide Gradle settings. 2 | # 3 | # For more details on how to configure your build environment visit 4 | # http://www.gradle.org/docs/current/userguide/build_environment.html 5 | # 6 | # Specifies the JVM arguments used for the daemon process. 7 | # The setting is particularly useful for tweaking memory settings. 8 | # Default value: -Xmx1024m -XX:MaxPermSize=256m 9 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 10 | # 11 | # When configured, Gradle will run in incubating parallel mode. 12 | # This option should only be used with decoupled projects. More details, visit 13 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 14 | # org.gradle.parallel=true 15 | #Wed Apr 18 14:01:51 CST 2018 16 | android.defaults.buildfeatures.buildconfig=true 17 | android.enableJetifier=true 18 | android.nonFinalResIds=false 19 | android.nonTransitiveRClass=false 20 | android.useAndroidX=true 21 | org.gradle.jvmargs=-Xmx1536m 22 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexLiuSheng/CheckVersionLib/23ab03936b0bbd78c447ef8d4d10bfba4243e4cf/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Sep 24 17:24:55 CST 2019 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /library.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexLiuSheng/CheckVersionLib/23ab03936b0bbd78c447ef8d4d10bfba4243e4cf/library.jar -------------------------------------------------------------------------------- /library/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /library/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'kotlin-android' 3 | //apply plugin: 'kotlin-android-extensions' 4 | android { 5 | compileSdkVersion 32 6 | // buildToolsVersion "29.0.3" 7 | resourcePrefix "versionchecklib" 8 | defaultConfig { 9 | minSdkVersion 21 10 | targetSdkVersion 32 11 | } 12 | 13 | buildTypes { 14 | 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | namespace 'com.allenliu.versionchecklib' 21 | lint { 22 | abortOnError false 23 | } 24 | compileOptions { 25 | targetCompatibility JavaVersion.VERSION_17 26 | sourceCompatibility JavaVersion.VERSION_17 27 | } 28 | } 29 | 30 | dependencies { 31 | implementation fileTree(include: ['*.jar'], dir: 'libs') 32 | implementation 'androidx.appcompat:appcompat:1.5.1' 33 | implementation 'com.squareup.okhttp3:okhttp:4.10.0' 34 | implementation 'org.greenrobot:eventbus:3.3.1' 35 | implementation "androidx.annotation:annotation:1.6.0" 36 | } 37 | -------------------------------------------------------------------------------- /library/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexLiuSheng/CheckVersionLib/23ab03936b0bbd78c447ef8d4d10bfba4243e4cf/library/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /library/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Dec 28 10:00:20 PST 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip 7 | -------------------------------------------------------------------------------- /library/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /library/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /library/local.properties: -------------------------------------------------------------------------------- 1 | ## This file is automatically generated by Android Studio. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must *NOT* be checked into Version Control Systems, 5 | # as it contains information specific to your local configuration. 6 | # 7 | # Location of the SDK. This is only used by Gradle. 8 | # For customization when using a Version Control System, please read the 9 | # header note. 10 | #Wed Feb 22 19:27:35 CST 2017 11 | sdk.dir=D\:\\androidsdk 12 | -------------------------------------------------------------------------------- /library/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\Eclipse\android-sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /library/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 16 | 17 | 18 | 23 | 26 | 27 | 28 | 32 | 33 | 34 | 38 | 39 | 43 | 47 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /library/src/main/java/com/allenliu/versionchecklib/callback/APKDownloadListener.java: -------------------------------------------------------------------------------- 1 | package com.allenliu.versionchecklib.callback; 2 | 3 | import java.io.File; 4 | 5 | /** 6 | * Created by allenliu on 2017/8/16. 7 | */ 8 | 9 | public interface APKDownloadListener { 10 | void onDownloading(int progress); 11 | void onDownloadSuccess(File file); 12 | void onDownloadFail(); 13 | } 14 | -------------------------------------------------------------------------------- /library/src/main/java/com/allenliu/versionchecklib/callback/CommitClickListener.java: -------------------------------------------------------------------------------- 1 | package com.allenliu.versionchecklib.callback; 2 | 3 | /** 4 | * Created by Allen Liu on 2017/2/23. 5 | */ 6 | 7 | public interface CommitClickListener { 8 | void onCommitClick(); 9 | } -------------------------------------------------------------------------------- /library/src/main/java/com/allenliu/versionchecklib/callback/DialogDismissListener.java: -------------------------------------------------------------------------------- 1 | package com.allenliu.versionchecklib.callback; 2 | 3 | import android.app.Dialog; 4 | import android.content.DialogInterface; 5 | 6 | /** 7 | * Created by Allen Liu on 2017/2/23. 8 | */ 9 | 10 | 11 | public interface DialogDismissListener { 12 | void dialogDismiss(DialogInterface dialog); 13 | 14 | } 15 | -------------------------------------------------------------------------------- /library/src/main/java/com/allenliu/versionchecklib/callback/DownloadListener.java: -------------------------------------------------------------------------------- 1 | package com.allenliu.versionchecklib.callback; 2 | 3 | import java.io.File; 4 | 5 | /** 6 | * Created by allenliu on 2017/8/16. 7 | */ 8 | 9 | public interface DownloadListener { 10 | void onCheckerDownloading(int progress); 11 | void onCheckerDownloadSuccess(File file); 12 | void onCheckerDownloadFail(); 13 | void onCheckerStartDownload(); 14 | } 15 | -------------------------------------------------------------------------------- /library/src/main/java/com/allenliu/versionchecklib/callback/OnCancelListener.java: -------------------------------------------------------------------------------- 1 | package com.allenliu.versionchecklib.callback; 2 | 3 | /** 4 | * Created by mac on 2018/5/14. 5 | */ 6 | 7 | public interface OnCancelListener { 8 | void onCancel(); 9 | } 10 | -------------------------------------------------------------------------------- /library/src/main/java/com/allenliu/versionchecklib/core/JumpActivity.java: -------------------------------------------------------------------------------- 1 | package com.allenliu.versionchecklib.core; 2 | 3 | import android.os.Bundle; 4 | 5 | import com.allenliu.versionchecklib.v2.eventbus.AllenEventType; 6 | import com.allenliu.versionchecklib.v2.eventbus.CommonEvent; 7 | import com.allenliu.versionchecklib.v2.ui.AllenBaseActivity; 8 | 9 | import org.greenrobot.eventbus.EventBus; 10 | 11 | /** 12 | * 不再库里做权限处理,默认下载路径为应用下载目录 13 | */ 14 | public class JumpActivity extends AllenBaseActivity { 15 | 16 | @Override 17 | protected void onCreate(Bundle savedInstanceState) { 18 | super.onCreate(savedInstanceState); 19 | sendBroadcast(true); 20 | return; 21 | // Should we show an explanation? 22 | // Show an expanation to the user *asynchronously* -- don't block 23 | // this thread waiting for the user's response! After the user 24 | // sees the explanation, try again to request the permission. 25 | // if(!downloadUrl.isEmpty()) 26 | // downloadAPK(downloadUrl,null); 27 | // No explanation needed, we can request the permission. 28 | // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an 29 | // app-defined int constant. The callback method gets the 30 | // result of the request. 31 | } 32 | 33 | @Override 34 | public void showDefaultDialog() { 35 | 36 | } 37 | 38 | @Override 39 | public void showCustomDialog() { 40 | 41 | } 42 | 43 | private void sendBroadcast(boolean result) { 44 | 45 | //post event 46 | CommonEvent commonEvent = new CommonEvent(); 47 | commonEvent.setEventType(AllenEventType.START_DOWNLOAD_APK); 48 | commonEvent.setSuccessful(true); 49 | commonEvent.setData(result); 50 | EventBus.getDefault().post(commonEvent); 51 | 52 | finish(); 53 | } 54 | 55 | 56 | 57 | } 58 | -------------------------------------------------------------------------------- /library/src/main/java/com/allenliu/versionchecklib/core/VersionFileProvider.java: -------------------------------------------------------------------------------- 1 | package com.allenliu.versionchecklib.core; 2 | 3 | import androidx.core.content.FileProvider; 4 | 5 | /** 6 | * Created by Allen Liu on 2017/2/28. 7 | */ 8 | 9 | public class VersionFileProvider extends FileProvider { 10 | } 11 | -------------------------------------------------------------------------------- /library/src/main/java/com/allenliu/versionchecklib/core/http/AllenHttp.java: -------------------------------------------------------------------------------- 1 | package com.allenliu.versionchecklib.core.http; 2 | 3 | 4 | import android.os.Build; 5 | 6 | import com.allenliu.versionchecklib.utils.ALog; 7 | import com.allenliu.versionchecklib.v2.builder.RequestVersionBuilder; 8 | 9 | import org.json.JSONException; 10 | import org.json.JSONObject; 11 | 12 | import java.security.SecureRandom; 13 | import java.security.cert.CertificateException; 14 | import java.security.cert.X509Certificate; 15 | import java.util.Map; 16 | import java.util.concurrent.TimeUnit; 17 | 18 | import javax.net.ssl.HostnameVerifier; 19 | import javax.net.ssl.SSLContext; 20 | import javax.net.ssl.SSLSession; 21 | import javax.net.ssl.SSLSocketFactory; 22 | import javax.net.ssl.TrustManager; 23 | import javax.net.ssl.X509TrustManager; 24 | 25 | import okhttp3.FormBody; 26 | import okhttp3.MediaType; 27 | import okhttp3.OkHttpClient; 28 | import okhttp3.Request; 29 | import okhttp3.RequestBody; 30 | 31 | /** 32 | * Created by allenliu on 2017/8/31. 33 | */ 34 | 35 | public class AllenHttp { 36 | private static OkHttpClient client; 37 | 38 | public static OkHttpClient getHttpClient() { 39 | if (client == null) { 40 | OkHttpClient.Builder builder = new OkHttpClient.Builder(); 41 | builder.sslSocketFactory(createSSLSocketFactory(),new TrustAllCerts()); 42 | builder.connectTimeout(15,TimeUnit.SECONDS); 43 | builder.hostnameVerifier(new TrustAllHostnameVerifier()); 44 | client=builder.build(); 45 | } 46 | return client; 47 | } 48 | 49 | private static class TrustAllHostnameVerifier implements HostnameVerifier { 50 | @Override 51 | public boolean verify(String hostname, SSLSession session) { 52 | return true; 53 | } 54 | } 55 | 56 | private static SSLSocketFactory createSSLSocketFactory() { 57 | SSLSocketFactory ssfFactory = null; 58 | 59 | try { 60 | SSLContext sc = SSLContext.getInstance("TLS"); 61 | sc.init(null, new TrustManager[]{new TrustAllCerts()}, new SecureRandom()); 62 | 63 | ssfFactory = sc.getSocketFactory(); 64 | } catch (Exception e) { 65 | } 66 | 67 | return ssfFactory; 68 | } 69 | 70 | private static class TrustAllCerts implements X509TrustManager { 71 | @Override 72 | public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { 73 | } 74 | 75 | @Override 76 | public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { 77 | } 78 | 79 | @Override 80 | public X509Certificate[] getAcceptedIssuers() { 81 | return new X509Certificate[0]; 82 | } 83 | } 84 | 85 | 86 | private static String assembleUrl(String url, HttpParams params) { 87 | 88 | StringBuffer urlBuilder = new StringBuffer(url); 89 | if (params != null) { 90 | urlBuilder.append("?"); 91 | for (Map.Entry stringObjectEntry : params.entrySet()) { 92 | String key = stringObjectEntry.getKey(); 93 | String value = stringObjectEntry.getValue() + ""; 94 | urlBuilder.append(key).append("=").append(value).append("&"); 95 | } 96 | url = urlBuilder.substring(0, urlBuilder.length() - 1); 97 | } 98 | ALog.e("url:" + url); 99 | return url; 100 | } 101 | 102 | 103 | private static String getRequestParamsJson(HttpParams params) { 104 | String json = null; 105 | if (params != null) { 106 | JSONObject jsonObject = new JSONObject(); 107 | for (Map.Entry entry : params.entrySet()) { 108 | try { 109 | jsonObject.put(entry.getKey(), entry.getValue()); 110 | } catch (JSONException e) { 111 | e.printStackTrace(); 112 | } 113 | } 114 | 115 | json = jsonObject.toString(); 116 | } 117 | ALog.e("json:" + json); 118 | return json; 119 | } 120 | 121 | /**********************************V2.0 Using RequestBuilder ************************************************************************/ 122 | 123 | private static T assembleHeader(T builder, RequestVersionBuilder versionParams) { 124 | com.allenliu.versionchecklib.core.http.HttpHeaders headers = versionParams.getHttpHeaders(); 125 | if (headers != null) { 126 | ALog.e("header:"); 127 | for (Map.Entry stringStringEntry : headers.entrySet()) { 128 | String key = stringStringEntry.getKey(); 129 | String value = stringStringEntry.getValue(); 130 | ALog.e(key + "=" + value + "\n"); 131 | builder.addHeader(key, value); 132 | } 133 | } 134 | return builder; 135 | } 136 | public static Request.Builder get(RequestVersionBuilder versionParams) { 137 | Request.Builder builder = new Request.Builder(); 138 | assembleHeader(builder, versionParams); 139 | builder.url(assembleUrl(versionParams.getRequestUrl(), versionParams.getRequestParams())); 140 | 141 | return builder; 142 | } 143 | 144 | public static Request.Builder post(RequestVersionBuilder versionParams) { 145 | FormBody formBody = getRequestParams(versionParams); 146 | Request.Builder builder = new Request.Builder(); 147 | assembleHeader(builder, versionParams); 148 | builder.post(formBody).url(versionParams.getRequestUrl()); 149 | return builder; 150 | } 151 | 152 | public static Request.Builder postJson(RequestVersionBuilder versionParams) { 153 | MediaType JSON = MediaType.parse("application/json; charset=utf-8"); 154 | String json = getRequestParamsJson(versionParams.getRequestParams()); 155 | RequestBody body = RequestBody.create(JSON, json); 156 | Request.Builder builder = new Request.Builder(); 157 | assembleHeader(builder, versionParams); 158 | builder.post(body).url(versionParams.getRequestUrl()); 159 | return builder; 160 | } 161 | 162 | private static FormBody getRequestParams(RequestVersionBuilder versionParams) { 163 | FormBody.Builder builder = new FormBody.Builder(); 164 | HttpParams params = versionParams.getRequestParams(); 165 | //#https://github.com/AlexLiuSheng/CheckVersionLib/issues/293 166 | if(params!=null) { 167 | for (Map.Entry entry : params.entrySet()) { 168 | builder.add(entry.getKey(), entry.getValue() + ""); 169 | ALog.e("params key:" + entry.getKey() + "-----value:" + entry.getValue()); 170 | } 171 | } 172 | return builder.build(); 173 | } 174 | 175 | } 176 | -------------------------------------------------------------------------------- /library/src/main/java/com/allenliu/versionchecklib/core/http/FileCallBack.java: -------------------------------------------------------------------------------- 1 | package com.allenliu.versionchecklib.core.http; 2 | 3 | 4 | import android.os.Handler; 5 | import android.os.Looper; 6 | 7 | import com.allenliu.versionchecklib.utils.ALog; 8 | 9 | import java.io.File; 10 | import java.io.FileOutputStream; 11 | import java.io.IOException; 12 | import java.io.InputStream; 13 | 14 | import okhttp3.Call; 15 | import okhttp3.Callback; 16 | import okhttp3.Response; 17 | 18 | /** 19 | * Created by allenliu on 2017/8/31. 20 | */ 21 | 22 | public abstract class FileCallBack implements Callback { 23 | private String path; 24 | private String name; 25 | private Handler handler; 26 | 27 | public FileCallBack(String path, String name) { 28 | this.path = path; 29 | this.name = name; 30 | handler = new Handler(Looper.getMainLooper()); 31 | } 32 | 33 | @Override 34 | public void onFailure(Call call, IOException e) { 35 | 36 | handler.post(new Runnable() { 37 | @Override 38 | public void run() { 39 | onDownloadFailed(); 40 | } 41 | }); 42 | 43 | } 44 | 45 | @Override 46 | public void onResponse(final Call call, final Response response) { 47 | if(!response.isSuccessful()){ 48 | handler.post(new Runnable() { 49 | @Override 50 | public void run() { 51 | onDownloadFailed(); 52 | 53 | } 54 | }); 55 | return; 56 | } 57 | InputStream is = null; 58 | byte[] buf = new byte[2048]; 59 | int len = 0; 60 | FileOutputStream fos = null; 61 | // 储存下载文件的目录 62 | File pathFile = new File(path); 63 | if (!pathFile.exists()) { 64 | pathFile.mkdirs(); 65 | } 66 | 67 | try { 68 | is = response.body().byteStream(); 69 | long total; 70 | final File file = new File(path, name); 71 | if (file.exists()) { 72 | file.delete(); 73 | } else { 74 | file.createNewFile(); 75 | } 76 | fos = new FileOutputStream(file); 77 | long sum = 0; 78 | while ((len = is.read(buf)) != -1) { 79 | total = response.body().contentLength(); 80 | // ALog.e("file total size:"+total); 81 | fos.write(buf, 0, len); 82 | sum += len; 83 | final int progress = (int) (((double) sum / total) * 100); 84 | // 下载中 85 | handler.post(new Runnable() { 86 | @Override 87 | public void run() { 88 | onDownloading(progress); 89 | } 90 | }); 91 | 92 | } 93 | fos.flush(); 94 | handler.post(new Runnable() { 95 | @Override 96 | public void run() { 97 | onSuccess(file, call, response); 98 | 99 | } 100 | }); 101 | 102 | } catch (Exception e) { 103 | e.printStackTrace(); 104 | handler.post(new Runnable() { 105 | @Override 106 | public void run() { 107 | onDownloadFailed(); 108 | 109 | } 110 | }); 111 | } finally { 112 | try { 113 | if (is != null) 114 | is.close(); 115 | if (fos != null) 116 | fos.close(); 117 | } catch (IOException e) { 118 | e.printStackTrace(); 119 | } 120 | } 121 | } 122 | 123 | 124 | public abstract void onSuccess(File file, Call call, Response response); 125 | 126 | public abstract void onDownloading(int progress); 127 | 128 | public abstract void onDownloadFailed(); 129 | } 130 | -------------------------------------------------------------------------------- /library/src/main/java/com/allenliu/versionchecklib/core/http/HttpHeaders.java: -------------------------------------------------------------------------------- 1 | package com.allenliu.versionchecklib.core.http; 2 | 3 | import java.io.Serializable; 4 | import java.util.LinkedHashMap; 5 | 6 | /** 7 | * Created by allenliu on 2017/8/31. 8 | */ 9 | 10 | public class HttpHeaders extends LinkedHashMap implements Serializable{ 11 | } 12 | -------------------------------------------------------------------------------- /library/src/main/java/com/allenliu/versionchecklib/core/http/HttpParams.java: -------------------------------------------------------------------------------- 1 | package com.allenliu.versionchecklib.core.http; 2 | 3 | import java.io.Serializable; 4 | import java.util.LinkedHashMap; 5 | 6 | public class HttpParams extends LinkedHashMapimplements Serializable { 7 | 8 | 9 | } -------------------------------------------------------------------------------- /library/src/main/java/com/allenliu/versionchecklib/core/http/HttpRequestMethod.java: -------------------------------------------------------------------------------- 1 | package com.allenliu.versionchecklib.core.http; 2 | 3 | /** 4 | * Created by Allen Liu on 2017/2/22. 5 | */ 6 | 7 | public enum HttpRequestMethod { 8 | POST,GET, POSTJSON 9 | 10 | } 11 | -------------------------------------------------------------------------------- /library/src/main/java/com/allenliu/versionchecklib/utils/ALog.java: -------------------------------------------------------------------------------- 1 | package com.allenliu.versionchecklib.utils; 2 | 3 | import android.util.Log; 4 | 5 | /** 6 | * Created by allenliu on 2017/8/16. 7 | */ 8 | 9 | public class ALog { 10 | private static final boolean debug = true; 11 | 12 | public static void e(String msg) { 13 | if (debug) { 14 | if (msg != null && !msg.isEmpty()) 15 | Log.e("Allen Checker", msg); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /library/src/main/java/com/allenliu/versionchecklib/utils/AllenEventBusUtil.java: -------------------------------------------------------------------------------- 1 | package com.allenliu.versionchecklib.utils; 2 | 3 | import com.allenliu.versionchecklib.v2.eventbus.CommonEvent; 4 | 5 | import org.greenrobot.eventbus.EventBus; 6 | 7 | /** 8 | * Created by allenliu on 2018/1/18. 9 | */ 10 | 11 | public class AllenEventBusUtil { 12 | public static void sendEventBus(int eventType) { 13 | CommonEvent commonEvent = new CommonEvent(); 14 | commonEvent.setSuccessful(true); 15 | commonEvent.setEventType(eventType); 16 | EventBus.getDefault().post(commonEvent); 17 | } 18 | public static void sendEventBusStick(int eventType) { 19 | CommonEvent commonEvent = new CommonEvent(); 20 | commonEvent.setSuccessful(true); 21 | commonEvent.setEventType(eventType); 22 | EventBus.getDefault().postSticky(commonEvent); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /library/src/main/java/com/allenliu/versionchecklib/utils/AppUtils.java: -------------------------------------------------------------------------------- 1 | package com.allenliu.versionchecklib.utils; /** 2 | * Copyright 2014 Zhenguo Jin 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import android.content.Context; 18 | import android.content.Intent; 19 | import android.content.pm.PackageInfo; 20 | import android.content.pm.PackageManager; 21 | import android.net.Uri; 22 | import android.os.Build; 23 | 24 | import com.allenliu.versionchecklib.core.VersionFileProvider; 25 | import com.allenliu.versionchecklib.v2.AllenVersionChecker; 26 | import com.allenliu.versionchecklib.v2.callback.CustomInstallListener; 27 | 28 | import java.io.File; 29 | 30 | /** 31 | * 32 | */ 33 | public final class AppUtils { 34 | 35 | /** 36 | * Don't let anyone instantiate this class. 37 | */ 38 | private AppUtils() { 39 | throw new Error("Do not need instantiate!"); 40 | } 41 | 42 | public static void installApk(Context context, File file) { 43 | Intent intent = new Intent(); 44 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 45 | intent.setAction(Intent.ACTION_VIEW); 46 | Uri uri; 47 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { 48 | uri = VersionFileProvider.getUriForFile(context, context.getPackageName() + ".versionProvider", file); 49 | intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); 50 | } else { 51 | uri = Uri.fromFile(file); 52 | } 53 | intent.setDataAndType(uri, 54 | "application/vnd.android.package-archive"); 55 | context.startActivity(intent); 56 | AllenVersionChecker.getInstance().cancelAllMission(); 57 | } 58 | 59 | public static void installApk(Context context, File file, CustomInstallListener listener) { 60 | Intent intent = new Intent(); 61 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 62 | intent.setAction(Intent.ACTION_VIEW); 63 | Uri uri; 64 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { 65 | uri = VersionFileProvider.getUriForFile(context, context.getPackageName() + ".versionProvider", file); 66 | intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); 67 | } else { 68 | uri = Uri.fromFile(file); 69 | } 70 | 71 | if (listener != null) { 72 | listener.install(context, uri); 73 | } else { 74 | intent.setDataAndType(uri, 75 | "application/vnd.android.package-archive"); 76 | context.startActivity(intent); 77 | 78 | AllenVersionChecker.getInstance().cancelAllMission(); 79 | } 80 | } 81 | 82 | public static boolean checkAPKIsExists(Context context, String downloadPath) { 83 | return checkAPKIsExists(context, downloadPath, null); 84 | 85 | } 86 | 87 | /** 88 | * @param context 89 | * @param downloadPath 90 | * @param newestVersionCode 开发者认为的最新的版本号 91 | * @return 92 | */ 93 | public static boolean checkAPKIsExists(Context context, String downloadPath, Integer newestVersionCode) { 94 | File file = new File(downloadPath); 95 | boolean result = false; 96 | if (file.exists()) { 97 | try { 98 | PackageManager pm = context.getPackageManager(); 99 | PackageInfo info = pm.getPackageArchiveInfo(downloadPath, 100 | PackageManager.GET_ACTIVITIES); 101 | //判断安装包存在并且包名一样并且版本号不一样 102 | ALog.e("本地安装包版本号:" + info.versionCode + "\n 当前app版本号:" + context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionCode); 103 | if (context.getPackageName().equalsIgnoreCase(info.packageName) && context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionCode != info.versionCode) { 104 | //判断开发者传入的最新版本号是否大于缓存包的版本号,大于那么相当于没有缓存 105 | if (newestVersionCode != null && info.versionCode < newestVersionCode) { 106 | result = false; 107 | } else 108 | result = true; 109 | 110 | } 111 | } catch (Exception e) { 112 | result = false; 113 | } 114 | } 115 | return result; 116 | 117 | } 118 | 119 | } -------------------------------------------------------------------------------- /library/src/main/java/com/allenliu/versionchecklib/utils/FileHelper.java: -------------------------------------------------------------------------------- 1 | package com.allenliu.versionchecklib.utils; 2 | 3 | import android.content.Context; 4 | import android.os.Build; 5 | import android.os.Environment; 6 | 7 | import androidx.annotation.NonNull; 8 | 9 | import java.io.File; 10 | 11 | public class FileHelper { 12 | @Deprecated 13 | public static String getDownloadApkCachePath() { 14 | 15 | String appCachePath = null; 16 | 17 | 18 | if (checkSDCard()) { 19 | 20 | appCachePath = Environment.getExternalStorageDirectory() + "/AllenVersionPath/"; 21 | } else { 22 | appCachePath = Environment.getDataDirectory().getPath() + "/AllenVersionPath/"; 23 | } 24 | File file = new File(appCachePath); 25 | if (!file.exists()) { 26 | file.mkdirs(); 27 | } 28 | return appCachePath; 29 | } 30 | 31 | public static String getDownloadApkCachePath(Context context) { 32 | String appCachePath; 33 | if (checkSDCard()) { 34 | if (Build.VERSION.SDK_INT >= 29) { 35 | appCachePath = context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath() + "/AllenVersionPath/"; 36 | } else { 37 | appCachePath = context.getExternalCacheDir() + "/AllenVersionPath/"; 38 | } 39 | 40 | } else { 41 | appCachePath = context.getFilesDir().getAbsolutePath() + "/AllenVersionPath/"; 42 | 43 | } 44 | 45 | 46 | File file = new File(appCachePath); 47 | if (!file.exists()) { 48 | file.mkdirs(); 49 | } 50 | return appCachePath; 51 | } 52 | 53 | 54 | /** 55 | * 56 | */ 57 | private static boolean checkSDCard() { 58 | 59 | return Environment.getExternalStorageState().equals( 60 | Environment.MEDIA_MOUNTED); 61 | 62 | } 63 | 64 | 65 | public static String dealDownloadPath(@NonNull String downloadAPKPath) { 66 | if (!downloadAPKPath.endsWith(File.separator)) { 67 | downloadAPKPath += File.separator; 68 | } 69 | return downloadAPKPath; 70 | 71 | } 72 | } -------------------------------------------------------------------------------- /library/src/main/java/com/allenliu/versionchecklib/v2/AllenVersionChecker.java: -------------------------------------------------------------------------------- 1 | package com.allenliu.versionchecklib.v2; 2 | 3 | import android.content.Context; 4 | 5 | import androidx.annotation.Nullable; 6 | 7 | import com.allenliu.versionchecklib.core.http.AllenHttp; 8 | import com.allenliu.versionchecklib.utils.AllenEventBusUtil; 9 | import com.allenliu.versionchecklib.v2.builder.DownloadBuilder; 10 | import com.allenliu.versionchecklib.v2.builder.RequestVersionBuilder; 11 | import com.allenliu.versionchecklib.v2.builder.UIData; 12 | import com.allenliu.versionchecklib.v2.eventbus.AllenEventType; 13 | 14 | /** 15 | * Created by allenliu on 2018/1/12. 16 | */ 17 | 18 | public class AllenVersionChecker { 19 | 20 | // public AllenVersionChecker() { 21 | // throw new RuntimeException("AllenVersionChecker can not be instantiated from outside"); 22 | // } 23 | private AllenVersionChecker() { 24 | 25 | } 26 | 27 | public static AllenVersionChecker getInstance() { 28 | return AllenVersionCheckerHolder.allenVersionChecker; 29 | } 30 | 31 | private static class AllenVersionCheckerHolder { 32 | public static final AllenVersionChecker allenVersionChecker = new AllenVersionChecker(); 33 | } 34 | 35 | @Deprecated 36 | public void cancelAllMission(Context context) { 37 | cancelAllMission(); 38 | } 39 | 40 | public void cancelAllMission() { 41 | AllenHttp.getHttpClient().dispatcher().cancelAll(); 42 | // Intent intent = new Intent(context.getApplicationContext(), VersionService.class); 43 | // context.getApplicationContext().stopService(intent); 44 | AllenEventBusUtil.sendEventBusStick(AllenEventType.CLOSE); 45 | AllenEventBusUtil.sendEventBusStick(AllenEventType.STOP_SERVICE); 46 | } 47 | 48 | /** 49 | * @param versionBundle developer should return version bundle ,to use when showing UI page,could be null 50 | * @return download builder for download setting 51 | */ 52 | public DownloadBuilder downloadOnly(@Nullable UIData versionBundle) { 53 | return new DownloadBuilder(null, versionBundle); 54 | } 55 | 56 | /** 57 | * use request version function 58 | * 59 | * @return requestVersionBuilder 60 | */ 61 | public RequestVersionBuilder requestVersion() { 62 | return new RequestVersionBuilder(); 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /library/src/main/java/com/allenliu/versionchecklib/v2/builder/BuilderManager.kt: -------------------------------------------------------------------------------- 1 | package com.allenliu.versionchecklib.v2.builder 2 | 3 | import android.annotation.SuppressLint 4 | import android.content.Context 5 | import com.allenliu.versionchecklib.R 6 | import com.allenliu.versionchecklib.utils.ALog 7 | import com.allenliu.versionchecklib.utils.AppUtils 8 | import com.allenliu.versionchecklib.v2.AllenVersionChecker 9 | import java.io.File 10 | 11 | /** 12 | * @author : shengliu7 13 | * @e-mail : shengliu7@iflytek.com 14 | * @date : 2020/12/19 12:34 PM 15 | * @desc : 16 | * 17 | */ 18 | @SuppressLint("StaticFieldLeak") 19 | object BuilderManager { 20 | private var downloadBuilder: DownloadBuilder? = null 21 | lateinit var context: Context 22 | fun getDownloadBuilder(): DownloadBuilder? { 23 | return downloadBuilder 24 | } 25 | 26 | fun init(context: Context, downloadBuilder: DownloadBuilder): BuilderManager { 27 | this.context = context 28 | this.downloadBuilder = downloadBuilder 29 | return this 30 | } 31 | 32 | fun destroy() { 33 | downloadBuilder = null 34 | } 35 | 36 | /** 37 | * 验证安装包是否存在,并且在安装成功情况下删除安装包 38 | */ 39 | fun checkAndDeleteAPK() { 40 | doWhenNotNull { 41 | //判断versioncode与当前版本不一样的apk是否存在,存在删除安装包 42 | try { 43 | val downloadPath: String = downloadAPKPath + context.getString(R.string.versionchecklib_download_apkname, context.packageName) 44 | if (!AppUtils.checkAPKIsExists(context, downloadPath)) { 45 | ALog.e("删除本地apk") 46 | File(downloadPath).delete() 47 | } 48 | } catch (e: Exception) { 49 | e.printStackTrace() 50 | } 51 | } 52 | 53 | } 54 | 55 | fun checkForceUpdate() { 56 | doWhenNotNull { 57 | forceUpdateListener?.onShouldForceUpdate() 58 | } 59 | } 60 | 61 | fun doWhenNotNull(nullBlock: (() -> T)? = null, block: DownloadBuilder.() -> T): T? { 62 | val builder = downloadBuilder 63 | if (builder != null) { 64 | return builder.block() 65 | 66 | } else { 67 | nullBlock?.invoke() 68 | AllenVersionChecker.getInstance().cancelAllMission() 69 | } 70 | return null 71 | } 72 | 73 | } -------------------------------------------------------------------------------- /library/src/main/java/com/allenliu/versionchecklib/v2/builder/DownloadBuilder.java: -------------------------------------------------------------------------------- 1 | package com.allenliu.versionchecklib.v2.builder; 2 | 3 | import android.content.Context; 4 | import android.content.pm.ApplicationInfo; 5 | import android.content.pm.PackageManager; 6 | 7 | import androidx.annotation.NonNull; 8 | 9 | import com.allenliu.versionchecklib.callback.APKDownloadListener; 10 | import com.allenliu.versionchecklib.callback.CommitClickListener; 11 | import com.allenliu.versionchecklib.callback.OnCancelListener; 12 | import com.allenliu.versionchecklib.utils.FileHelper; 13 | import com.allenliu.versionchecklib.v2.callback.CustomDownloadFailedListener; 14 | import com.allenliu.versionchecklib.v2.callback.CustomDownloadingDialogListener; 15 | import com.allenliu.versionchecklib.v2.callback.CustomInstallListener; 16 | import com.allenliu.versionchecklib.v2.callback.CustomVersionDialogListener; 17 | import com.allenliu.versionchecklib.v2.callback.ForceUpdateListener; 18 | import com.allenliu.versionchecklib.v2.net.RequestVersionManager; 19 | import com.allenliu.versionchecklib.v2.ui.VersionService; 20 | 21 | /** 22 | * Created by allenliu on 2018/1/12. 23 | */ 24 | 25 | public class DownloadBuilder { 26 | private RequestVersionBuilder requestVersionBuilder; 27 | private boolean isSilentDownload; 28 | private String downloadAPKPath; 29 | private boolean isForceRedownload; 30 | private String downloadUrl; 31 | private boolean isShowDownloadingDialog; 32 | private boolean isShowNotification; 33 | private boolean runOnForegroundService; 34 | private boolean isShowDownloadFailDialog; 35 | private boolean isDirectDownload; 36 | private NotificationBuilder notificationBuilder; 37 | private APKDownloadListener apkDownloadListener; 38 | 39 | private CustomDownloadFailedListener customDownloadFailedListener; 40 | private CustomDownloadingDialogListener customDownloadingDialogListener; 41 | private CustomVersionDialogListener customVersionDialogListener; 42 | private CustomInstallListener customInstallListener; 43 | private OnCancelListener onCancelListener; 44 | private CommitClickListener readyDownloadCommitClickListener; 45 | private CommitClickListener downloadFailedCommitClickListener; 46 | private OnCancelListener downloadingCancelListener; 47 | private OnCancelListener downloadFailedCancelListener; 48 | private OnCancelListener readyDownloadCancelListener; 49 | 50 | private ForceUpdateListener forceUpdateListener; 51 | private UIData versionBundle; 52 | private Integer newestVersionCode; 53 | private String apkName; 54 | 55 | 56 | public DownloadBuilder() { 57 | throw new RuntimeException("can not be instantiated from outside"); 58 | } 59 | 60 | private void initialize() { 61 | isSilentDownload = false; 62 | // downloadAPKPath = FileHelper.getDownloadApkCachePath(); 63 | isForceRedownload = false; 64 | isShowDownloadingDialog = true; 65 | isShowNotification = true; 66 | isDirectDownload = false; 67 | isShowDownloadFailDialog = true; 68 | notificationBuilder = NotificationBuilder.create(); 69 | runOnForegroundService = true; 70 | } 71 | 72 | public DownloadBuilder(RequestVersionBuilder requestVersionBuilder, UIData versionBundle) { 73 | this.requestVersionBuilder = requestVersionBuilder; 74 | this.versionBundle = versionBundle; 75 | initialize(); 76 | } 77 | 78 | 79 | public ForceUpdateListener getForceUpdateListener() { 80 | return forceUpdateListener; 81 | } 82 | 83 | public DownloadBuilder setForceUpdateListener(ForceUpdateListener forceUpdateListener) { 84 | this.forceUpdateListener = forceUpdateListener; 85 | return this; 86 | } 87 | 88 | public DownloadBuilder setApkName(String apkName) { 89 | this.apkName = apkName; 90 | return this; 91 | } 92 | 93 | public DownloadBuilder setVersionBundle(@NonNull UIData versionBundle) { 94 | this.versionBundle = versionBundle; 95 | return this; 96 | } 97 | 98 | public UIData getVersionBundle() { 99 | return versionBundle; 100 | } 101 | 102 | public DownloadBuilder setOnCancelListener(OnCancelListener cancelListener) { 103 | this.onCancelListener = cancelListener; 104 | return this; 105 | } 106 | 107 | public DownloadBuilder setCustomDownloadFailedListener(CustomDownloadFailedListener customDownloadFailedListener) { 108 | this.customDownloadFailedListener = customDownloadFailedListener; 109 | return this; 110 | } 111 | 112 | public DownloadBuilder setCustomDownloadingDialogListener(CustomDownloadingDialogListener customDownloadingDialogListener) { 113 | this.customDownloadingDialogListener = customDownloadingDialogListener; 114 | return this; 115 | } 116 | 117 | public DownloadBuilder setCustomVersionDialogListener(CustomVersionDialogListener customVersionDialogListener) { 118 | this.customVersionDialogListener = customVersionDialogListener; 119 | return this; 120 | } 121 | 122 | public DownloadBuilder setCustomDownloadInstallListener(CustomInstallListener customDownloadInstallListener) { 123 | this.customInstallListener = customDownloadInstallListener; 124 | return this; 125 | } 126 | 127 | public boolean isRunOnForegroundService() { 128 | return runOnForegroundService; 129 | } 130 | 131 | public DownloadBuilder setRunOnForegroundService(boolean runOnForegroundService) { 132 | this.runOnForegroundService = runOnForegroundService; 133 | return this; 134 | } 135 | 136 | public DownloadBuilder setSilentDownload(boolean silentDownload) { 137 | isSilentDownload = silentDownload; 138 | return this; 139 | } 140 | 141 | public Integer getNewestVersionCode() { 142 | return newestVersionCode; 143 | } 144 | 145 | public DownloadBuilder setNewestVersionCode(Integer newestVersionCode) { 146 | this.newestVersionCode = newestVersionCode; 147 | return this; 148 | } 149 | 150 | public DownloadBuilder setDownloadAPKPath(String downloadAPKPath) { 151 | this.downloadAPKPath = downloadAPKPath; 152 | return this; 153 | } 154 | 155 | public DownloadBuilder setForceRedownload(boolean forceRedownload) { 156 | isForceRedownload = forceRedownload; 157 | return this; 158 | } 159 | 160 | public DownloadBuilder setDownloadUrl(@NonNull String downloadUrl) { 161 | this.downloadUrl = downloadUrl; 162 | return this; 163 | } 164 | 165 | public DownloadBuilder setShowDownloadingDialog(boolean showDownloadingDialog) { 166 | isShowDownloadingDialog = showDownloadingDialog; 167 | return this; 168 | } 169 | 170 | public DownloadBuilder setShowNotification(boolean showNotification) { 171 | isShowNotification = showNotification; 172 | return this; 173 | } 174 | 175 | public DownloadBuilder setShowDownloadFailDialog(boolean showDownloadFailDialog) { 176 | isShowDownloadFailDialog = showDownloadFailDialog; 177 | return this; 178 | } 179 | 180 | public DownloadBuilder setApkDownloadListener(APKDownloadListener apkDownloadListener) { 181 | this.apkDownloadListener = apkDownloadListener; 182 | return this; 183 | } 184 | 185 | public CommitClickListener getReadyDownloadCommitClickListener() { 186 | return readyDownloadCommitClickListener; 187 | } 188 | 189 | public DownloadBuilder setReadyDownloadCommitClickListener(CommitClickListener readyDownloadCommitClickListener) { 190 | this.readyDownloadCommitClickListener = readyDownloadCommitClickListener; 191 | return this; 192 | } 193 | 194 | public CommitClickListener getDownloadFailedCommitClickListener() { 195 | return downloadFailedCommitClickListener; 196 | } 197 | 198 | public DownloadBuilder setDownloadFailedCommitClickListener(CommitClickListener downloadFailedCommitClickListener) { 199 | this.downloadFailedCommitClickListener = downloadFailedCommitClickListener; 200 | return this; 201 | } 202 | 203 | public OnCancelListener getDownloadingCancelListener() { 204 | return downloadingCancelListener; 205 | } 206 | 207 | public DownloadBuilder setDownloadingCancelListener(OnCancelListener downloadingCancelListener) { 208 | this.downloadingCancelListener = downloadingCancelListener; 209 | return this; 210 | } 211 | 212 | public OnCancelListener getDownloadFailedCancelListener() { 213 | return downloadFailedCancelListener; 214 | } 215 | 216 | public DownloadBuilder setDownloadFailedCancelListener(OnCancelListener downloadFailedCancelListener) { 217 | this.downloadFailedCancelListener = downloadFailedCancelListener; 218 | return this; 219 | } 220 | 221 | public OnCancelListener getReadyDownloadCancelListener() { 222 | return readyDownloadCancelListener; 223 | } 224 | 225 | public DownloadBuilder setReadyDownloadCancelListener(OnCancelListener readyDownloadCancelListener) { 226 | this.readyDownloadCancelListener = readyDownloadCancelListener; 227 | return this; 228 | } 229 | 230 | public boolean isSilentDownload() { 231 | return isSilentDownload; 232 | } 233 | 234 | public String getDownloadAPKPath() { 235 | return downloadAPKPath; 236 | } 237 | 238 | public boolean isForceRedownload() { 239 | return isForceRedownload; 240 | } 241 | 242 | public String getDownloadUrl() { 243 | return downloadUrl; 244 | } 245 | 246 | public boolean isShowDownloadingDialog() { 247 | return isShowDownloadingDialog; 248 | } 249 | 250 | public boolean isShowNotification() { 251 | return isShowNotification; 252 | } 253 | 254 | public boolean isShowDownloadFailDialog() { 255 | return isShowDownloadFailDialog; 256 | } 257 | 258 | public APKDownloadListener getApkDownloadListener() { 259 | return apkDownloadListener; 260 | } 261 | 262 | 263 | public CustomDownloadFailedListener getCustomDownloadFailedListener() { 264 | return customDownloadFailedListener; 265 | } 266 | 267 | public OnCancelListener getOnCancelListener() { 268 | return onCancelListener; 269 | } 270 | 271 | public CustomDownloadingDialogListener getCustomDownloadingDialogListener() { 272 | return customDownloadingDialogListener; 273 | } 274 | 275 | public CustomInstallListener getCustomInstallListener() { 276 | return customInstallListener; 277 | } 278 | 279 | public CustomVersionDialogListener getCustomVersionDialogListener() { 280 | return customVersionDialogListener; 281 | } 282 | 283 | public RequestVersionBuilder getRequestVersionBuilder() { 284 | return requestVersionBuilder; 285 | } 286 | 287 | public NotificationBuilder getNotificationBuilder() { 288 | return notificationBuilder; 289 | } 290 | 291 | public DownloadBuilder setNotificationBuilder(NotificationBuilder notificationBuilder) { 292 | this.notificationBuilder = notificationBuilder; 293 | return this; 294 | } 295 | 296 | public String getApkName() { 297 | return apkName; 298 | } 299 | 300 | public boolean isDirectDownload() { 301 | return isDirectDownload; 302 | } 303 | 304 | public DownloadBuilder setDirectDownload(boolean directDownload) { 305 | isDirectDownload = directDownload; 306 | return this; 307 | } 308 | 309 | private void setupDefaultNotificationIcon(Context context) { 310 | if (notificationBuilder.getIcon() == 0) { 311 | final PackageManager pm = context.getPackageManager(); 312 | final ApplicationInfo applicationInfo; 313 | try { 314 | applicationInfo = pm.getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA); 315 | final int appIconResId = applicationInfo.icon; 316 | notificationBuilder.setIcon(appIconResId); 317 | } catch (PackageManager.NameNotFoundException e) { 318 | e.printStackTrace(); 319 | } 320 | } 321 | } 322 | 323 | public void executeMission(Context context) { 324 | if (apkName == null) { 325 | //https://github.com/AlexLiuSheng/CheckVersionLib/issues/338 326 | apkName = context.getApplicationContext().getPackageName().replaceAll("\\.", ""); 327 | } 328 | setupDefaultNotificationIcon(context); 329 | //fix path permission 330 | setupDownloadPath(context); 331 | // downloadAPKPath=context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).getPath() + "/"; 332 | if (checkWhetherNeedRequestVersion()) { 333 | RequestVersionManager.getInstance().requestVersion(this, context.getApplicationContext()); 334 | } else { 335 | download(context); 336 | } 337 | 338 | } 339 | 340 | private void setupDownloadPath(Context context) { 341 | if (downloadAPKPath == null) { 342 | downloadAPKPath = FileHelper.getDownloadApkCachePath(context); 343 | } 344 | downloadAPKPath = FileHelper.dealDownloadPath(downloadAPKPath); 345 | } 346 | 347 | public void download(Context context) { 348 | VersionService.Companion.enqueueWork(context.getApplicationContext(), this); 349 | } 350 | 351 | private boolean checkWhetherNeedRequestVersion() { 352 | if (getRequestVersionBuilder() != null) 353 | return true; 354 | else 355 | return false; 356 | } 357 | 358 | } 359 | -------------------------------------------------------------------------------- /library/src/main/java/com/allenliu/versionchecklib/v2/builder/NotificationBuilder.java: -------------------------------------------------------------------------------- 1 | package com.allenliu.versionchecklib.v2.builder; 2 | 3 | /** 4 | * Created by allenliu on 2018/1/19. 5 | */ 6 | 7 | public class NotificationBuilder { 8 | private int icon; 9 | private String contentTitle; 10 | private String ticker; 11 | private String contentText; 12 | private boolean isRingtone; 13 | 14 | public static NotificationBuilder create(){ 15 | return new NotificationBuilder(); 16 | } 17 | 18 | private NotificationBuilder() { 19 | 20 | // icon = R.mipmap.ic_launcher; 21 | isRingtone = true; 22 | } 23 | 24 | public int getIcon() { 25 | return icon; 26 | } 27 | 28 | public NotificationBuilder setIcon(int icon) { 29 | this.icon = icon; 30 | return this; 31 | } 32 | 33 | public String getContentTitle() { 34 | return contentTitle; 35 | } 36 | 37 | public NotificationBuilder setContentTitle(String contentTitle) { 38 | this.contentTitle = contentTitle; 39 | return this; 40 | } 41 | 42 | public String getTicker() { 43 | return ticker; 44 | } 45 | 46 | public NotificationBuilder setTicker(String ticker) { 47 | this.ticker = ticker; 48 | return this; 49 | } 50 | 51 | public String getContentText() { 52 | return contentText; 53 | } 54 | 55 | public NotificationBuilder setContentText(String contentText) { 56 | this.contentText = contentText; 57 | return this; 58 | } 59 | 60 | public boolean isRingtone() { 61 | return isRingtone; 62 | } 63 | 64 | public NotificationBuilder setRingtone(boolean ringtone) { 65 | isRingtone = ringtone; 66 | return this; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /library/src/main/java/com/allenliu/versionchecklib/v2/builder/RequestVersionBuilder.java: -------------------------------------------------------------------------------- 1 | package com.allenliu.versionchecklib.v2.builder; 2 | 3 | import com.allenliu.versionchecklib.v2.callback.RequestVersionListener; 4 | import com.allenliu.versionchecklib.core.http.HttpHeaders; 5 | import com.allenliu.versionchecklib.core.http.HttpParams; 6 | import com.allenliu.versionchecklib.core.http.HttpRequestMethod; 7 | 8 | /** 9 | * Created by allenliu on 2018/1/12. 10 | */ 11 | 12 | public class RequestVersionBuilder { 13 | private HttpRequestMethod requestMethod; 14 | private HttpParams requestParams; 15 | private String requestUrl; 16 | private com.allenliu.versionchecklib.core.http.HttpHeaders httpHeaders; 17 | private RequestVersionListener requestVersionListener; 18 | 19 | public RequestVersionBuilder() { 20 | requestMethod = HttpRequestMethod.GET; 21 | 22 | } 23 | 24 | public HttpRequestMethod getRequestMethod() { 25 | return requestMethod; 26 | } 27 | 28 | public RequestVersionBuilder setRequestMethod(HttpRequestMethod requestMethod) { 29 | this.requestMethod = requestMethod; 30 | return this; 31 | } 32 | 33 | public HttpParams getRequestParams() { 34 | return requestParams; 35 | } 36 | 37 | public RequestVersionBuilder setRequestParams(HttpParams requestParams) { 38 | this.requestParams = requestParams; 39 | return this; 40 | } 41 | 42 | public String getRequestUrl() { 43 | return requestUrl; 44 | } 45 | 46 | public RequestVersionBuilder setRequestUrl(String requestUrl) { 47 | this.requestUrl = requestUrl; 48 | return this; 49 | } 50 | 51 | public HttpHeaders getHttpHeaders() { 52 | return httpHeaders; 53 | } 54 | 55 | public RequestVersionBuilder setHttpHeaders(HttpHeaders httpHeaders) { 56 | this.httpHeaders = httpHeaders; 57 | return this; 58 | } 59 | 60 | public RequestVersionListener getRequestVersionListener() { 61 | return requestVersionListener; 62 | } 63 | 64 | /** 65 | * @param requestVersionListener requestVersionResultListener 66 | * @return download builder setting 67 | */ 68 | public DownloadBuilder request(RequestVersionListener requestVersionListener) { 69 | this.requestVersionListener = requestVersionListener; 70 | return new DownloadBuilder(this, null); 71 | } 72 | 73 | 74 | 75 | } 76 | -------------------------------------------------------------------------------- /library/src/main/java/com/allenliu/versionchecklib/v2/builder/UIData.java: -------------------------------------------------------------------------------- 1 | package com.allenliu.versionchecklib.v2.builder; 2 | 3 | import android.os.Bundle; 4 | 5 | /** 6 | * Created by allenliu on 2018/1/18. 7 | */ 8 | 9 | public class UIData { 10 | private final String TITLE = "title", CONTENT = "content", DOWNLOAD_URL = "download_url"; 11 | 12 | private Bundle versionBundle; 13 | 14 | public static UIData create() { 15 | return new UIData(); 16 | } 17 | 18 | public String getDownloadUrl() { 19 | return versionBundle.getString(DOWNLOAD_URL); 20 | } 21 | 22 | public UIData setDownloadUrl(String downloadUrl) { 23 | versionBundle.putString(DOWNLOAD_URL, downloadUrl); 24 | return this; 25 | } 26 | 27 | 28 | 29 | private UIData() { 30 | versionBundle = new Bundle(); 31 | versionBundle.putString(TITLE, "by `UIData.setTitle()` to set your update title"); 32 | versionBundle.putString(CONTENT, "by `UIData.setContent()` to set your update content "); 33 | } 34 | 35 | public UIData setTitle(String title) { 36 | versionBundle.putString(TITLE, title); 37 | return this; 38 | } 39 | 40 | public UIData setContent(String content) { 41 | versionBundle.putString(CONTENT, content); 42 | return this; 43 | } 44 | 45 | public String getTitle() { 46 | return versionBundle.getString(TITLE); 47 | } 48 | 49 | public String getContent() { 50 | return versionBundle.getString(CONTENT); 51 | } 52 | 53 | public Bundle getVersionBundle() { 54 | return versionBundle; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /library/src/main/java/com/allenliu/versionchecklib/v2/callback/CustomDownloadFailedListener.java: -------------------------------------------------------------------------------- 1 | package com.allenliu.versionchecklib.v2.callback; 2 | 3 | import android.app.Dialog; 4 | import android.content.Context; 5 | import android.os.Bundle; 6 | 7 | import com.allenliu.versionchecklib.v2.builder.UIData; 8 | 9 | /** 10 | * Created by allenliu on 2018/1/18. 11 | */ 12 | 13 | public interface CustomDownloadFailedListener { 14 | Dialog getCustomDownloadFailed(Context context,UIData versionBundle); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /library/src/main/java/com/allenliu/versionchecklib/v2/callback/CustomDownloadingDialogListener.java: -------------------------------------------------------------------------------- 1 | package com.allenliu.versionchecklib.v2.callback; 2 | 3 | import android.app.Dialog; 4 | import android.content.Context; 5 | import android.os.Bundle; 6 | 7 | import com.allenliu.versionchecklib.v2.builder.UIData; 8 | 9 | /** 10 | * Created by allenliu on 2018/1/18. 11 | */ 12 | 13 | public interface CustomDownloadingDialogListener { 14 | Dialog getCustomDownloadingDialog(Context context, int progress, UIData versionBundle); 15 | 16 | void updateUI(Dialog dialog, int progress, UIData versionBundle); 17 | } 18 | -------------------------------------------------------------------------------- /library/src/main/java/com/allenliu/versionchecklib/v2/callback/CustomInstallListener.java: -------------------------------------------------------------------------------- 1 | package com.allenliu.versionchecklib.v2.callback; 2 | 3 | import android.content.Context; 4 | import android.net.Uri; 5 | 6 | /** 7 | * @author weishu 8 | * date 2018/12/19. 9 | */ 10 | public interface CustomInstallListener { 11 | void install(Context context, Uri apk); 12 | } 13 | -------------------------------------------------------------------------------- /library/src/main/java/com/allenliu/versionchecklib/v2/callback/CustomVersionDialogListener.java: -------------------------------------------------------------------------------- 1 | package com.allenliu.versionchecklib.v2.callback; 2 | 3 | import android.app.Dialog; 4 | import android.content.Context; 5 | import android.os.Bundle; 6 | 7 | import com.allenliu.versionchecklib.v2.builder.UIData; 8 | 9 | /** 10 | * Created by allenliu on 2018/1/18. 11 | */ 12 | 13 | public interface CustomVersionDialogListener { 14 | Dialog getCustomVersionDialog(Context context,UIData versionBundle); 15 | } 16 | -------------------------------------------------------------------------------- /library/src/main/java/com/allenliu/versionchecklib/v2/callback/DownloadListenerKt.kt: -------------------------------------------------------------------------------- 1 | package com.allenliu.versionchecklib.v2.callback 2 | 3 | import com.allenliu.versionchecklib.callback.DownloadListener 4 | 5 | /** 6 | * @author : shengliu7 7 | * @e-mail : shengliu7@iflytek.com 8 | * @date : 2020/12/19 2:51 PM 9 | * @desc : 10 | * 11 | */ 12 | interface DownloadListenerKt : DownloadListener, LifecycleListener { 13 | } -------------------------------------------------------------------------------- /library/src/main/java/com/allenliu/versionchecklib/v2/callback/ForceUpdateListener.java: -------------------------------------------------------------------------------- 1 | package com.allenliu.versionchecklib.v2.callback; 2 | 3 | /** 4 | * Created by allenliu on 2018/1/18. 5 | */ 6 | 7 | public interface ForceUpdateListener { 8 | void onShouldForceUpdate(); 9 | } 10 | -------------------------------------------------------------------------------- /library/src/main/java/com/allenliu/versionchecklib/v2/callback/LifecycleListener.kt: -------------------------------------------------------------------------------- 1 | package com.allenliu.versionchecklib.v2.callback 2 | 3 | import com.allenliu.versionchecklib.v2.builder.BuilderManager 4 | 5 | /** 6 | * @author : shengliu7 7 | * @e-mail : shengliu7@iflytek.com 8 | * @date : 2020/12/19 2:18 PM 9 | * @desc : 10 | * 11 | */ 12 | interface LifecycleListener { 13 | fun isDisposed() = 14 | BuilderManager.getDownloadBuilder() == null 15 | 16 | } -------------------------------------------------------------------------------- /library/src/main/java/com/allenliu/versionchecklib/v2/callback/RequestVersionListener.java: -------------------------------------------------------------------------------- 1 | package com.allenliu.versionchecklib.v2.callback; 2 | 3 | import androidx.annotation.Nullable; 4 | 5 | import com.allenliu.versionchecklib.v2.builder.DownloadBuilder; 6 | import com.allenliu.versionchecklib.v2.builder.UIData; 7 | 8 | /** 9 | * Created by allenliu on 2018/1/12. 10 | */ 11 | 12 | public interface RequestVersionListener { 13 | /** 14 | * @param result the result string of request 15 | * @return developer should return version bundle ,to use when showing UI page,could be null 16 | */ 17 | @Nullable 18 | UIData onRequestVersionSuccess(DownloadBuilder downloadBuilder, String result); 19 | 20 | void onRequestVersionFailure(String message); 21 | 22 | } 23 | -------------------------------------------------------------------------------- /library/src/main/java/com/allenliu/versionchecklib/v2/eventbus/AllenEventType.java: -------------------------------------------------------------------------------- 1 | package com.allenliu.versionchecklib.v2.eventbus; 2 | 3 | /** 4 | * Created by allenliu on 2018/1/18. 5 | */ 6 | 7 | public class AllenEventType { 8 | public static final int SHOW_VERSION_DIALOG = 0x61; 9 | public static final int START_DOWNLOAD_APK = 0x62; 10 | // public static final int REQUEST_PERMISSION = 0X63; 11 | public static final int UPDATE_DOWNLOADING_PROGRESS = 0X64; 12 | public static final int DOWNLOAD_COMPLETE = 0X65; 13 | public static final int CLOSE_DOWNLOADING_ACTIVITY = 0x66; 14 | public static final int CLOSE = 0x68; 15 | public static final int STOP_SERVICE = 0X67; 16 | ; 17 | } 18 | -------------------------------------------------------------------------------- /library/src/main/java/com/allenliu/versionchecklib/v2/eventbus/BaseEvent.java: -------------------------------------------------------------------------------- 1 | package com.allenliu.versionchecklib.v2.eventbus; 2 | 3 | /** 4 | * Created by Allen Liu on 2018/01/18. 5 | */ 6 | 7 | public class BaseEvent { 8 | private int eventType; 9 | 10 | public int getEventType() { 11 | return eventType; 12 | } 13 | 14 | public BaseEvent setEventType(int eventType) { 15 | this.eventType = eventType; 16 | return this; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /library/src/main/java/com/allenliu/versionchecklib/v2/eventbus/CommonEvent.java: -------------------------------------------------------------------------------- 1 | package com.allenliu.versionchecklib.v2.eventbus; 2 | 3 | /** 4 | * Created by Allen Liu on 2018/01/18. 5 | */ 6 | 7 | public class CommonEvent extends BaseEvent { 8 | public boolean isSuccessful() { 9 | return isSuccessful; 10 | } 11 | 12 | public CommonEvent setSuccessful(boolean successful) { 13 | isSuccessful = successful; 14 | return this; 15 | } 16 | 17 | private boolean isSuccessful; 18 | private String message; 19 | private T data; 20 | 21 | public int getResponseCode() { 22 | return responseCode; 23 | } 24 | 25 | public CommonEvent setResponseCode(int responseCode) { 26 | this.responseCode = responseCode; 27 | return this; 28 | } 29 | 30 | private int responseCode; 31 | 32 | public String getMessage() { 33 | return message; 34 | } 35 | 36 | public CommonEvent setMessage(String message) { 37 | this.message = message; 38 | return this; 39 | } 40 | 41 | public T getData() { 42 | return data; 43 | } 44 | 45 | public CommonEvent setData(T data) { 46 | this.data = data; 47 | return this; 48 | } 49 | public static CommonEvent getSimpleEvent(int type){ 50 | CommonEvent commonEvent=new CommonEvent(); 51 | commonEvent.setSuccessful(true); 52 | commonEvent.setEventType(type); 53 | return commonEvent; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /library/src/main/java/com/allenliu/versionchecklib/v2/net/DownloadMangerV2.java: -------------------------------------------------------------------------------- 1 | package com.allenliu.versionchecklib.v2.net; 2 | 3 | import android.os.Handler; 4 | import android.os.Looper; 5 | 6 | import com.allenliu.versionchecklib.core.http.AllenHttp; 7 | import com.allenliu.versionchecklib.core.http.FileCallBack; 8 | import com.allenliu.versionchecklib.v2.callback.DownloadListenerKt; 9 | 10 | import java.io.File; 11 | 12 | import okhttp3.Call; 13 | import okhttp3.Request; 14 | import okhttp3.Response; 15 | 16 | /** 17 | * Created by allenliu on 2018/1/18. 18 | */ 19 | 20 | public class DownloadMangerV2 { 21 | private static int sLastProgress = 0; 22 | 23 | public static void download(final String url, final String downloadApkPath, final String fileName, final DownloadListenerKt listener) { 24 | sLastProgress = 0; 25 | if (url != null && !url.isEmpty()) { 26 | Request request = new Request 27 | .Builder() 28 | //#issue 220 29 | .addHeader("Accept-Encoding", "identity") 30 | .url(url).build(); 31 | // mockDownload(listener); 32 | 33 | new Handler(Looper.getMainLooper()).post(new Runnable() { 34 | @Override 35 | public void run() { 36 | if (listener != null && !listener.isDisposed()) 37 | listener.onCheckerStartDownload(); 38 | } 39 | }); 40 | 41 | AllenHttp.getHttpClient().newCall(request).enqueue(new FileCallBack(downloadApkPath, fileName) { 42 | @Override 43 | public void onSuccess(final File file, Call call, Response response) { 44 | sLastProgress = 0; 45 | new Handler(Looper.getMainLooper()).post(new Runnable() { 46 | @Override 47 | public void run() { 48 | if (listener != null && !listener.isDisposed()) 49 | listener.onCheckerDownloadSuccess(file); 50 | } 51 | }); 52 | } 53 | 54 | @Override 55 | public void onDownloading(final int progress) { 56 | new Handler(Looper.getMainLooper()).post(new Runnable() { 57 | @Override 58 | public void run() { 59 | if (listener != null && !listener.isDisposed() && progress - sLastProgress > 5) { 60 | listener.onCheckerDownloading(progress); 61 | sLastProgress = progress; 62 | } 63 | 64 | 65 | } 66 | }); 67 | 68 | } 69 | 70 | @Override 71 | public void onDownloadFailed() { 72 | sLastProgress = 0; 73 | handleFailed(listener); 74 | } 75 | }); 76 | // 77 | 78 | } else { 79 | throw new RuntimeException("you must set download url for download function using"); 80 | } 81 | } 82 | 83 | private static void mockDownload(DownloadListenerKt listener) { 84 | new Handler(Looper.getMainLooper()).post(new Runnable() { 85 | @Override 86 | public void run() { 87 | if (listener != null && !listener.isDisposed()) 88 | listener.onCheckerStartDownload(); 89 | } 90 | }); 91 | for (int i = 0; i < 100; i++) { 92 | try { 93 | Thread.sleep(100); 94 | } catch (InterruptedException e) { 95 | throw new RuntimeException(e); 96 | } 97 | int finalI = i; 98 | new Handler(Looper.getMainLooper()).post(new Runnable() { 99 | @Override 100 | public void run() { 101 | if (listener != null && !listener.isDisposed()) 102 | listener.onCheckerDownloading(finalI); 103 | } 104 | }); 105 | } 106 | handleFailed(listener); 107 | } 108 | 109 | private static void handleFailed(final DownloadListenerKt listener) { 110 | new Handler(Looper.getMainLooper()).post(new Runnable() { 111 | @Override 112 | public void run() { 113 | if (listener != null && !listener.isDisposed()) 114 | listener.onCheckerDownloadFail(); 115 | 116 | } 117 | }); 118 | } 119 | 120 | } 121 | -------------------------------------------------------------------------------- /library/src/main/java/com/allenliu/versionchecklib/v2/net/RequestVersionManager.java: -------------------------------------------------------------------------------- 1 | package com.allenliu.versionchecklib.v2.net; 2 | 3 | import android.content.Context; 4 | import android.os.Handler; 5 | import android.os.Looper; 6 | 7 | import com.allenliu.versionchecklib.core.http.AllenHttp; 8 | import com.allenliu.versionchecklib.core.http.HttpRequestMethod; 9 | import com.allenliu.versionchecklib.utils.ALog; 10 | import com.allenliu.versionchecklib.v2.AllenVersionChecker; 11 | import com.allenliu.versionchecklib.v2.builder.BuilderManager; 12 | import com.allenliu.versionchecklib.v2.builder.DownloadBuilder; 13 | import com.allenliu.versionchecklib.v2.builder.RequestVersionBuilder; 14 | import com.allenliu.versionchecklib.v2.builder.UIData; 15 | import com.allenliu.versionchecklib.v2.callback.RequestVersionListener; 16 | 17 | import java.io.IOException; 18 | import java.util.concurrent.Executors; 19 | 20 | import okhttp3.OkHttpClient; 21 | import okhttp3.Request; 22 | import okhttp3.Response; 23 | 24 | /** 25 | * @author AllenLiu 26 | * @version 1.0 27 | * @date 2019/4/30 28 | * @since 1.0 29 | */ 30 | public class RequestVersionManager { 31 | // private boolean isCanceled=false; 32 | private final Handler handler = new Handler(Looper.getMainLooper()); 33 | 34 | public static RequestVersionManager getInstance() { 35 | return Holder.instance; 36 | } 37 | 38 | public static class Holder { 39 | static RequestVersionManager instance = new RequestVersionManager(); 40 | 41 | } 42 | /** 43 | * 请求版本接口 44 | * #issue 239 45 | */ 46 | public void requestVersion(final DownloadBuilder builder, final Context context) { 47 | // registerEventBus(); 48 | Executors.newSingleThreadExecutor().submit(new Runnable() { 49 | @Override 50 | public void run() { 51 | RequestVersionBuilder requestVersionBuilder = builder.getRequestVersionBuilder(); 52 | OkHttpClient client = AllenHttp.getHttpClient(); 53 | HttpRequestMethod requestMethod = requestVersionBuilder.getRequestMethod(); 54 | Request request = null; 55 | switch (requestMethod) { 56 | case GET: 57 | request = AllenHttp.get(requestVersionBuilder).build(); 58 | break; 59 | case POST: 60 | request = AllenHttp.post(requestVersionBuilder).build(); 61 | break; 62 | case POSTJSON: 63 | request = AllenHttp.postJson(requestVersionBuilder).build(); 64 | break; 65 | } 66 | final RequestVersionListener requestVersionListener = requestVersionBuilder.getRequestVersionListener(); 67 | if (requestVersionListener != null) { 68 | try { 69 | final Response response = client.newCall(request).execute(); 70 | if (response.isSuccessful()) { 71 | final String result = response.body() != null ? response.body().string() : null; 72 | post(new Runnable() { 73 | @Override 74 | public void run() { 75 | UIData versionBundle = requestVersionListener.onRequestVersionSuccess(builder, result); 76 | if (versionBundle != null) { 77 | builder.setVersionBundle(versionBundle); 78 | builder.download(context); 79 | } 80 | } 81 | 82 | 83 | }); 84 | } else { 85 | post(new Runnable() { 86 | @Override 87 | public void run() { 88 | requestVersionListener.onRequestVersionFailure(response.message()); 89 | AllenVersionChecker.getInstance().cancelAllMission(); 90 | } 91 | }); 92 | } 93 | } catch (final IOException e) { 94 | e.printStackTrace(); 95 | post(new Runnable() { 96 | @Override 97 | public void run() { 98 | requestVersionListener.onRequestVersionFailure(e.getMessage()); 99 | AllenVersionChecker.getInstance().cancelAllMission(); 100 | } 101 | }); 102 | } 103 | } else { 104 | ALog.e("using request version function,you must set a requestVersionListener"); 105 | 106 | } 107 | // unregister(); 108 | } 109 | }); 110 | 111 | } 112 | 113 | private void post(Runnable r) { 114 | handler.post(r); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /library/src/main/java/com/allenliu/versionchecklib/v2/ui/AllenBaseActivity.kt: -------------------------------------------------------------------------------- 1 | package com.allenliu.versionchecklib.v2.ui 2 | 3 | import android.R 4 | import android.annotation.TargetApi 5 | import android.app.Activity 6 | import android.graphics.Color 7 | import android.os.Build 8 | import android.os.Bundle 9 | import android.view.View 10 | import android.view.ViewGroup 11 | import android.view.WindowManager 12 | import androidx.appcompat.app.AppCompatActivity 13 | import com.allenliu.versionchecklib.v2.builder.BuilderManager.doWhenNotNull 14 | import com.allenliu.versionchecklib.v2.eventbus.AllenEventType 15 | import com.allenliu.versionchecklib.v2.eventbus.CommonEvent 16 | import org.greenrobot.eventbus.EventBus 17 | import org.greenrobot.eventbus.Subscribe 18 | import org.greenrobot.eventbus.ThreadMode 19 | 20 | /** 21 | * Created by allenliu on 2018/1/18. 22 | */ 23 | abstract class AllenBaseActivity : AppCompatActivity() { 24 | override fun onCreate(savedInstanceState: Bundle?) { 25 | super.onCreate(savedInstanceState) 26 | if (!EventBus.getDefault().isRegistered(this)) EventBus.getDefault().register(this) 27 | setTransparent(this) 28 | } 29 | 30 | override fun onStop() { 31 | super.onStop() 32 | } 33 | 34 | override fun onDestroy() { 35 | super.onDestroy() 36 | if (EventBus.getDefault().isRegistered(this)) EventBus.getDefault().unregister(this) 37 | } 38 | 39 | /** 40 | * 使状态栏透明 41 | */ 42 | @TargetApi(Build.VERSION_CODES.KITKAT) 43 | private fun transparentStatusBar(activity: Activity) { 44 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 45 | activity.window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) 46 | activity.window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) 47 | activity.window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION) 48 | activity.window.statusBarColor = Color.TRANSPARENT 49 | } else { 50 | activity.window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) 51 | } 52 | } 53 | 54 | /** 55 | * 设置根布局参数 56 | */ 57 | private fun setRootView(activity: Activity) { 58 | val parent = activity.findViewById(R.id.content) as ViewGroup 59 | var i = 0 60 | val count = parent.childCount 61 | while (i < count) { 62 | val childView = parent.getChildAt(i) 63 | if (childView is ViewGroup) { 64 | childView.setFitsSystemWindows(true) 65 | childView.clipToPadding = true 66 | } 67 | i++ 68 | } 69 | } 70 | 71 | fun setTransparent(activity: Activity) { 72 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { 73 | return 74 | } 75 | transparentStatusBar(activity) 76 | setRootView(activity) 77 | } 78 | 79 | protected fun throwWrongIdsException() { 80 | throw RuntimeException("customize dialog must use the specify id that lib gives") 81 | } 82 | 83 | protected fun checkForceUpdate() { 84 | doWhenNotNull { 85 | if (forceUpdateListener != null) { 86 | forceUpdateListener?.onShouldForceUpdate() 87 | finish() 88 | } 89 | } 90 | } 91 | 92 | protected fun cancelHandler() { 93 | doWhenNotNull { 94 | onCancelListener?.onCancel() 95 | if (this@AllenBaseActivity is UIActivity && readyDownloadCancelListener != null) { 96 | readyDownloadCancelListener?.onCancel() 97 | } else if (this@AllenBaseActivity is DownloadFailedActivity && downloadFailedCancelListener != null) { 98 | downloadFailedCancelListener?.onCancel() 99 | } else if (this@AllenBaseActivity is DownloadingActivity && downloadingCancelListener != null) { 100 | downloadingCancelListener?.onCancel() 101 | } else { 102 | null 103 | } 104 | } 105 | } 106 | 107 | @Subscribe(threadMode = ThreadMode.MAIN) 108 | open fun receiveEvent(commonEvent: CommonEvent<*>) { 109 | if (commonEvent.eventType == AllenEventType.CLOSE) { 110 | finish() 111 | EventBus.getDefault().removeStickyEvent(commonEvent) 112 | } 113 | } 114 | 115 | abstract fun showDefaultDialog() 116 | abstract fun showCustomDialog() 117 | override fun finish() { 118 | super.finish() 119 | overridePendingTransition(0, 0) 120 | } 121 | } 122 | 123 | 124 | -------------------------------------------------------------------------------- /library/src/main/java/com/allenliu/versionchecklib/v2/ui/DownloadFailedActivity.kt: -------------------------------------------------------------------------------- 1 | package com.allenliu.versionchecklib.v2.ui 2 | 3 | import android.app.Dialog 4 | import android.content.DialogInterface 5 | import android.os.Bundle 6 | import android.view.View 7 | import androidx.appcompat.app.AlertDialog 8 | import com.allenliu.versionchecklib.R 9 | import com.allenliu.versionchecklib.utils.ALog 10 | import com.allenliu.versionchecklib.utils.AllenEventBusUtil 11 | import com.allenliu.versionchecklib.v2.AllenVersionChecker 12 | import com.allenliu.versionchecklib.v2.builder.BuilderManager 13 | import com.allenliu.versionchecklib.v2.eventbus.AllenEventType 14 | import com.allenliu.versionchecklib.v2.eventbus.CommonEvent 15 | import org.greenrobot.eventbus.EventBus 16 | import org.greenrobot.eventbus.Subscribe 17 | import org.greenrobot.eventbus.ThreadMode 18 | 19 | class DownloadFailedActivity : AllenBaseActivity(), DialogInterface.OnCancelListener { 20 | private var downloadFailedDialog: Dialog? = null 21 | override fun onCreate(savedInstanceState: Bundle?) { 22 | super.onCreate(savedInstanceState) 23 | showDowloadFailedDialog() 24 | } 25 | 26 | override fun showDefaultDialog() { 27 | downloadFailedDialog = AlertDialog 28 | .Builder(this) 29 | .setMessage(getString(R.string.versionchecklib_download_fail_retry)) 30 | .setPositiveButton(getString(R.string.versionchecklib_confirm)) { _, _ -> retryDownload() } 31 | .setNegativeButton(getString(R.string.versionchecklib_cancel)) { d, _ -> onCancel(d) } 32 | .create().apply { 33 | setCanceledOnTouchOutside(false) 34 | setCancelable(true) 35 | show() 36 | } 37 | 38 | } 39 | 40 | override fun showCustomDialog() { 41 | BuilderManager.doWhenNotNull { 42 | downloadFailedDialog = customDownloadFailedListener.getCustomDownloadFailed(this@DownloadFailedActivity, versionBundle).apply { 43 | val retryView = findViewById(R.id.versionchecklib_failed_dialog_retry) 44 | retryView?.setOnClickListener { retryDownload() } 45 | val cancelView = findViewById(R.id.versionchecklib_failed_dialog_cancel) 46 | cancelView?.setOnClickListener { onCancel(this) } 47 | show() 48 | 49 | } 50 | 51 | } 52 | } 53 | 54 | private fun showDowloadFailedDialog() { 55 | AllenEventBusUtil.sendEventBusStick(AllenEventType.CLOSE_DOWNLOADING_ACTIVITY) 56 | BuilderManager.doWhenNotNull { 57 | if (customDownloadFailedListener != null) { 58 | ALog.e("show customization failed dialog") 59 | showCustomDialog() 60 | } else { 61 | ALog.e("show default failed dialog") 62 | showDefaultDialog() 63 | } 64 | downloadFailedDialog?.setOnCancelListener(this@DownloadFailedActivity) 65 | } 66 | 67 | } 68 | 69 | override fun onCancel(dialogInterface: DialogInterface) { 70 | ALog.e("on cancel" + 71 | "") 72 | cancelHandler() 73 | checkForceUpdate() 74 | AllenVersionChecker.getInstance().cancelAllMission() 75 | finish() 76 | } 77 | 78 | private fun retryDownload() { 79 | //增加commit 回调 80 | BuilderManager.doWhenNotNull { 81 | downloadFailedCommitClickListener?.onCommitClick() 82 | } 83 | AllenEventBusUtil.sendEventBus(AllenEventType.START_DOWNLOAD_APK) 84 | 85 | } 86 | 87 | override fun onStop() { 88 | super.onStop() 89 | if (downloadFailedDialog != null && downloadFailedDialog!!.isShowing) downloadFailedDialog!!.dismiss() 90 | } 91 | 92 | override fun onPause() { 93 | super.onPause() 94 | 95 | // finish(); 96 | } 97 | 98 | override fun onResume() { 99 | super.onResume() 100 | if (downloadFailedDialog != null && !downloadFailedDialog!!.isShowing) downloadFailedDialog!!.show() 101 | } 102 | @Subscribe(threadMode = ThreadMode.MAIN) 103 | override fun receiveEvent(commonEvent: CommonEvent<*>) { 104 | super.receiveEvent(commonEvent) 105 | when (commonEvent.eventType) { 106 | AllenEventType.START_DOWNLOAD_APK -> { 107 | finish() 108 | } 109 | 110 | } 111 | } 112 | } -------------------------------------------------------------------------------- /library/src/main/java/com/allenliu/versionchecklib/v2/ui/DownloadingActivity.kt: -------------------------------------------------------------------------------- 1 | package com.allenliu.versionchecklib.v2.ui 2 | 3 | import android.app.Dialog 4 | import android.content.DialogInterface 5 | import android.os.Bundle 6 | import android.view.LayoutInflater 7 | import android.view.View 8 | import android.widget.ProgressBar 9 | import android.widget.TextView 10 | import androidx.appcompat.app.AlertDialog 11 | import com.allenliu.versionchecklib.R 12 | import com.allenliu.versionchecklib.core.http.AllenHttp 13 | import com.allenliu.versionchecklib.utils.ALog 14 | import com.allenliu.versionchecklib.v2.builder.BuilderManager 15 | import com.allenliu.versionchecklib.v2.eventbus.AllenEventType 16 | import com.allenliu.versionchecklib.v2.eventbus.CommonEvent 17 | import org.greenrobot.eventbus.EventBus 18 | 19 | class DownloadingActivity : AllenBaseActivity(), DialogInterface.OnCancelListener { 20 | private var downloadingDialog: Dialog? = null 21 | private var currentProgress = 0 22 | protected var isDestroy = false 23 | override fun onCreate(savedInstanceState: Bundle?) { 24 | super.onCreate(savedInstanceState) 25 | ALog.e("loading activity create") 26 | showLoadingDialog() 27 | } 28 | 29 | fun onCancel(isDownloadCompleted: Boolean) { 30 | if (!isDownloadCompleted) { 31 | //should cancel downloading http request if it is force update action 32 | BuilderManager.doWhenNotNull { 33 | forceUpdateListener?.let { 34 | AllenHttp.getHttpClient().dispatcher.cancelAll() 35 | } 36 | } 37 | cancelHandler() 38 | checkForceUpdate() 39 | } 40 | finish() 41 | } 42 | 43 | override fun onCancel(dialog: DialogInterface) { 44 | onCancel(false) 45 | } 46 | 47 | override fun receiveEvent(commonEvent: CommonEvent<*>) { 48 | super.receiveEvent(commonEvent) 49 | when (commonEvent.eventType) { 50 | AllenEventType.UPDATE_DOWNLOADING_PROGRESS -> { 51 | val progress = commonEvent.data as Int 52 | currentProgress = progress 53 | updateProgress() 54 | } 55 | 56 | AllenEventType.DOWNLOAD_COMPLETE -> onCancel(true) 57 | AllenEventType.CLOSE_DOWNLOADING_ACTIVITY -> { 58 | destroy() 59 | EventBus.getDefault().removeStickyEvent(commonEvent) 60 | } 61 | } 62 | } 63 | 64 | override fun showDefaultDialog() { 65 | val loadingView = LayoutInflater.from(this).inflate(R.layout.downloading_layout, null) 66 | downloadingDialog = 67 | AlertDialog.Builder(this).setTitle("").setView(loadingView).create().apply { 68 | BuilderManager.doWhenNotNull { 69 | if (forceUpdateListener != null) setCancelable(false) else setCancelable(true) 70 | setCanceledOnTouchOutside(false) 71 | val pb = loadingView.findViewById(R.id.pb) 72 | val tvProgress = loadingView.findViewById(R.id.tv_progress) 73 | tvProgress.text = 74 | String.format(getString(R.string.versionchecklib_progress), currentProgress) 75 | pb.progress = currentProgress 76 | show() 77 | } 78 | 79 | } 80 | 81 | } 82 | 83 | override fun showCustomDialog() { 84 | BuilderManager.doWhenNotNull { 85 | downloadingDialog = customDownloadingDialogListener.getCustomDownloadingDialog( 86 | this@DownloadingActivity, 87 | currentProgress, 88 | versionBundle 89 | ).apply { 90 | if (forceUpdateListener != null) setCancelable(false) else setCancelable(true) 91 | val cancelView = findViewById(R.id.versionchecklib_loading_dialog_cancel) 92 | cancelView?.setOnClickListener { onCancel(false) } 93 | show() 94 | } 95 | } 96 | 97 | 98 | } 99 | 100 | override fun onStop() { 101 | super.onStop() 102 | //#issue350 103 | destroyWithOutDismiss() 104 | isDestroy = true 105 | } 106 | 107 | override fun onPause() { 108 | super.onPause() 109 | 110 | } 111 | 112 | override fun onResume() { 113 | super.onResume() 114 | isDestroy = false 115 | downloadingDialog?.let { 116 | if (!it.isShowing) { 117 | it.show() 118 | } 119 | } 120 | 121 | } 122 | 123 | private fun destroyWithOutDismiss() { 124 | downloadingDialog?.let { 125 | if (it.isShowing) { 126 | it.dismiss() 127 | } 128 | } 129 | } 130 | 131 | private fun destroy() { 132 | ALog.e("loading activity destroy") 133 | destroyWithOutDismiss() 134 | finish() 135 | } 136 | 137 | private fun updateProgress() { 138 | if (!isDestroy) { 139 | BuilderManager.doWhenNotNull { 140 | if (customDownloadingDialogListener != null) { 141 | customDownloadingDialogListener.updateUI( 142 | downloadingDialog, 143 | currentProgress, 144 | versionBundle 145 | ) 146 | } else { 147 | val pb = downloadingDialog?.findViewById(R.id.pb) 148 | pb?.progress = currentProgress 149 | val tvProgress = downloadingDialog?.findViewById(R.id.tv_progress) 150 | tvProgress?.text = 151 | String.format(getString(R.string.versionchecklib_progress), currentProgress) 152 | downloadingDialog?.show() 153 | } 154 | } 155 | 156 | } 157 | } 158 | 159 | private fun showLoadingDialog() { 160 | ALog.e("show loading") 161 | if (!isDestroy) { 162 | BuilderManager.doWhenNotNull { 163 | if (customDownloadingDialogListener != null) { 164 | showCustomDialog() 165 | } else { 166 | showDefaultDialog() 167 | } 168 | } 169 | downloadingDialog?.setOnCancelListener(this) 170 | } 171 | } 172 | 173 | companion object { 174 | const val PROGRESS = "progress" 175 | } 176 | } -------------------------------------------------------------------------------- /library/src/main/java/com/allenliu/versionchecklib/v2/ui/NotificationHelper.kt: -------------------------------------------------------------------------------- 1 | package com.allenliu.versionchecklib.v2.ui 2 | 3 | import android.app.Notification 4 | import android.app.NotificationChannel 5 | import android.app.NotificationManager 6 | import android.app.PendingIntent 7 | import android.content.Context 8 | import android.content.Intent 9 | import android.graphics.Color 10 | import android.media.RingtoneManager 11 | import android.net.Uri 12 | import android.os.Build 13 | import androidx.annotation.RequiresApi 14 | import androidx.core.app.NotificationCompat 15 | import com.allenliu.versionchecklib.R 16 | import com.allenliu.versionchecklib.core.JumpActivity 17 | import com.allenliu.versionchecklib.core.VersionFileProvider 18 | import com.allenliu.versionchecklib.utils.ALog 19 | import com.allenliu.versionchecklib.v2.builder.BuilderManager 20 | import com.allenliu.versionchecklib.v2.builder.DownloadBuilder 21 | import com.allenliu.versionchecklib.v2.builder.NotificationBuilder 22 | import java.io.File 23 | 24 | /** 25 | * Created by allenliu on 2018/1/19. 26 | */ 27 | class NotificationHelper(private val context: Context) { 28 | var notification: NotificationCompat.Builder? = null 29 | private val manager: NotificationManager = 30 | context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager 31 | private var isDownloadSuccess = false 32 | private var isFailed = false 33 | private var currentProgress = 0 34 | private var contentText: String? = null 35 | 36 | /** 37 | * update notification progress 38 | * 39 | * @param progress the progress of notification 40 | */ 41 | fun updateNotification(progress: Int) { 42 | 43 | BuilderManager.doWhenNotNull { 44 | if (isShowNotification) { 45 | notification?.let { 46 | 47 | if (progress - currentProgress > 5 && !isDownloadSuccess && !isFailed) { 48 | ALog.e("update progress notification") 49 | contentText?.let { text -> 50 | 51 | it.setContentText(String.format(text, progress)) 52 | it.setProgress(100, progress, false) 53 | manager.notify(NOTIFICATION_ID, it.build()) 54 | 55 | currentProgress = progress 56 | } 57 | 58 | 59 | } 60 | } 61 | 62 | } 63 | } 64 | 65 | } 66 | 67 | /** 68 | * show notification 69 | */ 70 | fun showNotification() { 71 | currentProgress = 0 72 | isDownloadSuccess = false 73 | isFailed = false 74 | 75 | BuilderManager.doWhenNotNull { 76 | if (isShowNotification) { 77 | ALog.e("reset notification") 78 | notification = createNotification(this) 79 | manager.notify(NOTIFICATION_ID, notification?.build()) 80 | } 81 | } 82 | 83 | } 84 | 85 | /** 86 | * show download success notification 87 | */ 88 | fun showDownloadCompleteNotifcation(file: File) { 89 | currentProgress = 0 90 | BuilderManager.doWhenNotNull { 91 | isDownloadSuccess = true 92 | if (!isShowNotification) return@doWhenNotNull 93 | val i = Intent(Intent.ACTION_VIEW) 94 | val uri: Uri 95 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { 96 | uri = VersionFileProvider.getUriForFile( 97 | context, 98 | context.packageName + ".versionProvider", 99 | file 100 | ) 101 | ALog.e(context.packageName + "") 102 | i.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) 103 | } else { 104 | uri = Uri.fromFile(file) 105 | } 106 | //设置intent的类型 107 | i.setDataAndType( 108 | uri, 109 | "application/vnd.android.package-archive" 110 | ) 111 | val pendingIntent = PendingIntent.getActivity( 112 | context, 113 | 0, 114 | i, 115 | PendingIntent.FLAG_IMMUTABLE 116 | ) 117 | createInstallNotification().apply { 118 | setContentIntent(pendingIntent) 119 | setContentText(context.getString(R.string.versionchecklib_download_finish)) 120 | manager.cancelAll() 121 | manager.notify(INSTALL_NOTIFICATION_ID, build()) 122 | } 123 | 124 | 125 | } 126 | 127 | } 128 | 129 | fun showDownloadFailedNotification() { 130 | isDownloadSuccess = false 131 | isFailed = true 132 | BuilderManager.doWhenNotNull { 133 | if (isShowNotification) { 134 | notification?.let { 135 | ALog.e("show download failed notification") 136 | val intent = Intent(context, JumpActivity::class.java) 137 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) 138 | val pendingIntent = 139 | PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE) 140 | it.setContentIntent(pendingIntent) 141 | it.setContentText(context.getString(R.string.versionchecklib_download_fail)) 142 | 143 | it.setProgress(0, 0, false) 144 | manager.notify(NOTIFICATION_ID, it.build()) 145 | } 146 | 147 | } 148 | } 149 | 150 | } 151 | 152 | private fun createNotification(versionBuilder: DownloadBuilder): NotificationCompat.Builder { 153 | 154 | val builder: NotificationCompat.Builder? 155 | val libNotificationBuilder: NotificationBuilder = versionBuilder.notificationBuilder 156 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { 157 | val notificationChannel = NotificationChannel( 158 | channelid, 159 | channelName, 160 | NotificationManager.IMPORTANCE_DEFAULT 161 | ) 162 | notificationChannel.enableLights(false) 163 | notificationChannel.lightColor = Color.RED 164 | notificationChannel.enableVibration(false) 165 | val manager = 166 | context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager 167 | manager.createNotificationChannel(notificationChannel) 168 | } 169 | builder = NotificationCompat.Builder(context, channelid) 170 | builder.setAutoCancel(true) 171 | builder.setSmallIcon(versionBuilder.notificationBuilder.icon) 172 | //set content title 173 | var contentTitle: String? = context.getString(R.string.app_name) 174 | if (libNotificationBuilder.contentTitle != null) contentTitle = 175 | libNotificationBuilder.contentTitle 176 | builder.setContentTitle(contentTitle) 177 | //set ticker 178 | var ticker: String? = context.getString(R.string.versionchecklib_downloading) 179 | if (libNotificationBuilder.ticker != null) ticker = libNotificationBuilder.ticker 180 | builder.setTicker(ticker) 181 | //set content text 182 | contentText = context.getString(R.string.versionchecklib_download_progress) 183 | if (libNotificationBuilder.contentText != null) contentText = 184 | libNotificationBuilder.contentText 185 | builder.setContentText(String.format(contentText!!, 0)) 186 | builder.setContentIntent(null); 187 | if (libNotificationBuilder.isRingtone) { 188 | val notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION) 189 | val r = RingtoneManager.getRingtone(context, notification) 190 | r?.play() 191 | } 192 | return builder 193 | } 194 | 195 | private fun createInstallNotification(): NotificationCompat.Builder { 196 | val notifcationBuilder = NotificationCompat.Builder(context, channelid) 197 | .setContentTitle(context.getString(R.string.app_name)) 198 | .setContentText(context.getString(R.string.versionchecklib_version_service_runing)) 199 | .setAutoCancel(false) 200 | 201 | BuilderManager.getDownloadBuilder()?.notificationBuilder?.icon?.let { 202 | notifcationBuilder.setSmallIcon( 203 | it 204 | ) 205 | } 206 | 207 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { 208 | val notificationChannel = NotificationChannel( 209 | channelid, 210 | "version_service_name", 211 | NotificationManager.IMPORTANCE_HIGH 212 | ) 213 | notificationChannel.enableLights(false) 214 | notificationChannel.enableVibration(false) 215 | val manager = 216 | context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager 217 | manager.createNotificationChannel(notificationChannel) 218 | } 219 | return notifcationBuilder 220 | } 221 | 222 | fun onDestroy() { 223 | manager.cancel(NOTIFICATION_ID) 224 | } 225 | 226 | // notificationChannel.setLightColor(getColor(R.color.versionchecklib_theme_color)); 227 | 228 | companion object { 229 | const val NOTIFICATION_ID = 1 230 | const val INSTALL_NOTIFICATION_ID = 2 231 | 232 | private const val channelid = "version_service_id" 233 | private const val channelName = "version_service_name" 234 | 235 | 236 | fun createSimpleNotification(context: Context): Notification { 237 | val notifcationBuilder = NotificationCompat.Builder(context, channelid) 238 | .setContentTitle(context.getString(R.string.app_name)) 239 | .setContentText(context.getString(R.string.versionchecklib_version_service_runing)) 240 | .setAutoCancel(false) 241 | 242 | BuilderManager.getDownloadBuilder()?.notificationBuilder?.icon?.let { 243 | notifcationBuilder.setSmallIcon( 244 | it 245 | ) 246 | } 247 | 248 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { 249 | val notificationChannel = NotificationChannel( 250 | channelid, 251 | channelName, NotificationManager.IMPORTANCE_HIGH 252 | ) 253 | notificationChannel.enableLights(false) 254 | notificationChannel.enableVibration(false) 255 | val manager = 256 | context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager 257 | manager.createNotificationChannel(notificationChannel) 258 | } 259 | return notifcationBuilder.build() 260 | } 261 | } 262 | 263 | init { 264 | currentProgress = 0 265 | } 266 | } -------------------------------------------------------------------------------- /library/src/main/java/com/allenliu/versionchecklib/v2/ui/UIActivity.kt: -------------------------------------------------------------------------------- 1 | package com.allenliu.versionchecklib.v2.ui 2 | 3 | import android.app.Dialog 4 | import android.content.DialogInterface 5 | import android.os.Bundle 6 | import android.view.View 7 | import androidx.appcompat.app.AlertDialog 8 | import com.allenliu.versionchecklib.R 9 | import com.allenliu.versionchecklib.utils.ALog 10 | import com.allenliu.versionchecklib.utils.AllenEventBusUtil 11 | import com.allenliu.versionchecklib.utils.AppUtils 12 | import com.allenliu.versionchecklib.v2.AllenVersionChecker 13 | import com.allenliu.versionchecklib.v2.builder.BuilderManager 14 | import com.allenliu.versionchecklib.v2.builder.DownloadBuilder 15 | import com.allenliu.versionchecklib.v2.builder.UIData 16 | import com.allenliu.versionchecklib.v2.eventbus.AllenEventType 17 | import java.io.File 18 | 19 | class UIActivity : AllenBaseActivity(), DialogInterface.OnCancelListener { 20 | private var versionDialog: Dialog? = null 21 | private var isDestroy = false 22 | override fun onCreate(savedInstanceState: Bundle?) { 23 | super.onCreate(savedInstanceState) 24 | ALog.e("version activity create") 25 | showVersionDialog() 26 | } 27 | 28 | override fun onDestroy() { 29 | isDestroy = true 30 | ALog.e("version activity destroy") 31 | super.onDestroy() 32 | } 33 | 34 | override fun showDefaultDialog() { 35 | val builder = BuilderManager.getDownloadBuilder() 36 | if (builder != null) { 37 | val uiData: UIData? = builder.versionBundle 38 | var title: String? = "提示" 39 | var content: String = "检测到新版本" 40 | if (uiData != null) { 41 | title = uiData.title 42 | content = uiData.content 43 | } 44 | val alertBuilder = AlertDialog.Builder(this).setTitle(title).setMessage(content).setPositiveButton(getString(R.string.versionchecklib_confirm)) { _, _ -> dealVersionDialogCommit() } 45 | if (builder.forceUpdateListener == null) { 46 | alertBuilder.setNegativeButton(getString(R.string.versionchecklib_cancel)) { d, _ -> onCancel(d) } 47 | alertBuilder.setCancelable(false) 48 | } else { 49 | alertBuilder.setCancelable(false) 50 | } 51 | versionDialog = alertBuilder.create().apply { 52 | setCanceledOnTouchOutside(false) 53 | show() 54 | } 55 | 56 | } 57 | } 58 | 59 | override fun showCustomDialog() { 60 | val builder = BuilderManager.getDownloadBuilder() ?: return 61 | ALog.e("show customization dialog") 62 | versionDialog = builder.customVersionDialogListener.getCustomVersionDialog(this, builder.versionBundle) 63 | .apply { 64 | try { 65 | //自定义dialog,commit button 必须存在 66 | val view = findViewById(R.id.versionchecklib_version_dialog_commit) 67 | if (view != null) { 68 | ALog.e("view not null") 69 | view.setOnClickListener { 70 | ALog.e("click") 71 | dealVersionDialogCommit() 72 | } 73 | } else { 74 | throwWrongIdsException() 75 | } 76 | //如果有取消按钮,id也必须对应 77 | val cancelView = findViewById(R.id.versionchecklib_version_dialog_cancel) 78 | cancelView?.setOnClickListener { onCancel(this) } 79 | } catch (e: Exception) { 80 | e.printStackTrace() 81 | throwWrongIdsException() 82 | } 83 | show() 84 | 85 | } 86 | 87 | } 88 | 89 | private fun showVersionDialog() { 90 | BuilderManager.doWhenNotNull { 91 | if (customVersionDialogListener != null) { 92 | showCustomDialog() 93 | } else { 94 | showDefaultDialog() 95 | } 96 | } 97 | versionDialog?.setOnCancelListener(this) 98 | 99 | } 100 | 101 | override fun onPause() { 102 | super.onPause() 103 | 104 | 105 | } 106 | 107 | override fun onStop() { 108 | super.onStop() 109 | versionDialog?.let { 110 | if (it.isShowing) { 111 | it.dismiss() 112 | } 113 | } 114 | } 115 | 116 | override fun onResume() { 117 | super.onResume() 118 | versionDialog?.let { 119 | if (!it.isShowing) { 120 | it.show() 121 | } 122 | } 123 | } 124 | 125 | private fun dealVersionDialogCommit() { 126 | val versionBuilder: DownloadBuilder? = BuilderManager.getDownloadBuilder() 127 | if (versionBuilder != null) { 128 | //增加commit 回调 129 | if (versionBuilder.readyDownloadCommitClickListener != null) { 130 | versionBuilder.readyDownloadCommitClickListener.onCommitClick() 131 | } 132 | //如果是静默下载直接安装 133 | if (versionBuilder.isSilentDownload) { 134 | val downloadPath = versionBuilder.downloadAPKPath + getString(R.string.versionchecklib_download_apkname, if (versionBuilder.apkName != null) versionBuilder.apkName else packageName) 135 | AppUtils.installApk(this, File(downloadPath), versionBuilder.customInstallListener) 136 | checkForceUpdate() 137 | //否定开始下载 138 | } else { 139 | AllenEventBusUtil.sendEventBus(AllenEventType.START_DOWNLOAD_APK) 140 | } 141 | finish() 142 | } 143 | } 144 | 145 | override fun onCancel(dialogInterface: DialogInterface) { 146 | cancelHandler() 147 | AllenVersionChecker.getInstance().cancelAllMission() 148 | finish() 149 | checkForceUpdate() 150 | } 151 | } -------------------------------------------------------------------------------- /library/src/main/java/com/allenliu/versionchecklib/v2/ui/VersionService.kt: -------------------------------------------------------------------------------- 1 | package com.allenliu.versionchecklib.v2.ui 2 | 3 | import android.app.Service 4 | import android.content.Context 5 | import android.content.Intent 6 | import android.os.Build 7 | import android.os.IBinder 8 | import androidx.annotation.WorkerThread 9 | import com.allenliu.versionchecklib.R 10 | import com.allenliu.versionchecklib.core.http.AllenHttp 11 | import com.allenliu.versionchecklib.utils.ALog 12 | import com.allenliu.versionchecklib.utils.AllenEventBusUtil 13 | import com.allenliu.versionchecklib.utils.AppUtils 14 | import com.allenliu.versionchecklib.v2.AllenVersionChecker 15 | import com.allenliu.versionchecklib.v2.builder.BuilderManager 16 | import com.allenliu.versionchecklib.v2.builder.DownloadBuilder 17 | import com.allenliu.versionchecklib.v2.callback.DownloadListenerKt 18 | import com.allenliu.versionchecklib.v2.eventbus.AllenEventType 19 | import com.allenliu.versionchecklib.v2.eventbus.CommonEvent 20 | import com.allenliu.versionchecklib.v2.net.DownloadMangerV2 21 | import org.greenrobot.eventbus.EventBus 22 | import org.greenrobot.eventbus.Subscribe 23 | import org.greenrobot.eventbus.ThreadMode 24 | import java.io.File 25 | import java.util.concurrent.ExecutorService 26 | import java.util.concurrent.Executors 27 | 28 | class VersionService : Service() { 29 | private var notificationHelper: NotificationHelper? = null 30 | private var isServiceAlive = false 31 | private var executors: ExecutorService? = null 32 | override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int { 33 | if (!EventBus.getDefault().isRegistered(this)) { 34 | EventBus.getDefault().register(this) 35 | } 36 | ALog.e("version service create") 37 | 38 | 39 | 40 | init() 41 | return START_REDELIVER_INTENT 42 | } 43 | 44 | companion object { 45 | fun enqueueWork(context: Context, builder: DownloadBuilder) { 46 | //清除之前的任务,如果有 47 | // AllenVersionChecker.getInstance().cancelAllMission() 48 | BuilderManager.init(context, builder) 49 | val intent = Intent(context, VersionService::class.java) 50 | //显示通知栏的情况 才设置为前台服务 51 | if (builder.isRunOnForegroundService && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { 52 | context.startForegroundService(intent) 53 | } else { 54 | context.startService(intent) 55 | } 56 | } 57 | } 58 | 59 | override fun onDestroy() { 60 | super.onDestroy() 61 | ALog.e("version service destroy") 62 | BuilderManager.doWhenNotNull { 63 | if (isRunOnForegroundService) { 64 | stopForeground(true) 65 | } 66 | } 67 | BuilderManager.destroy() 68 | notificationHelper?.onDestroy() 69 | isServiceAlive = false 70 | executors?.shutdown() 71 | AllenHttp.getHttpClient().dispatcher.cancelAll() 72 | if (EventBus.getDefault().isRegistered(this)) { 73 | EventBus.getDefault().unregister(this) 74 | } 75 | } 76 | 77 | override fun onBind(intent: Intent): IBinder? { 78 | return null 79 | } 80 | 81 | private fun onHandleWork() { 82 | downloadAPK() 83 | } 84 | 85 | private fun downloadAPK() { 86 | BuilderManager.doWhenNotNull { 87 | if (versionBundle != null) { 88 | if (isDirectDownload) { 89 | startDownloadApk() 90 | } else { 91 | if (isSilentDownload) { 92 | startDownloadApk() 93 | } else { 94 | showVersionDialog() 95 | } 96 | } 97 | } 98 | } 99 | 100 | } 101 | 102 | /** 103 | * 开启UI展示界面 104 | */ 105 | private fun showVersionDialog() { 106 | BuilderManager.doWhenNotNull { 107 | val intent = Intent(this@VersionService, UIActivity::class.java) 108 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) 109 | startActivity(intent) 110 | } 111 | 112 | } 113 | 114 | private fun showDownloadingDialog() { 115 | BuilderManager.doWhenNotNull { 116 | if (isShowDownloadingDialog) { 117 | val intent = Intent(this@VersionService, DownloadingActivity::class.java) 118 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) 119 | startActivity(intent) 120 | } 121 | 122 | } 123 | 124 | } 125 | 126 | private fun updateDownloadingDialogProgress(progress: Int) { 127 | val commonEvent: CommonEvent = CommonEvent() 128 | commonEvent.eventType = AllenEventType.UPDATE_DOWNLOADING_PROGRESS 129 | commonEvent.data = progress 130 | commonEvent.isSuccessful = true 131 | EventBus.getDefault().post(commonEvent) 132 | } 133 | 134 | private fun showDownloadFailedDialog() { 135 | BuilderManager.doWhenNotNull { 136 | val intent = Intent(this@VersionService, DownloadFailedActivity::class.java) 137 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) 138 | startActivity(intent) 139 | } 140 | 141 | 142 | } 143 | 144 | private fun requestPermissionAndDownload() { 145 | //不再请求权限 146 | startDownloadApk() 147 | // BuilderManager.doWhenNotNull { 148 | // val intent = Intent(this@VersionService, PermissionDialogActivity::class.java) 149 | // intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) 150 | // startActivity(intent) 151 | // } 152 | 153 | } 154 | 155 | private fun install() { 156 | BuilderManager.doWhenNotNull { 157 | AllenEventBusUtil.sendEventBus(AllenEventType.DOWNLOAD_COMPLETE) 158 | val downloadPath = downloadFilePath 159 | if (isSilentDownload) { 160 | showVersionDialog() 161 | } else { 162 | AppUtils.installApk(applicationContext, File(downloadPath), customInstallListener) 163 | BuilderManager.checkForceUpdate() 164 | } 165 | } 166 | 167 | } 168 | 169 | private val downloadFilePath: String 170 | get() { 171 | return BuilderManager.doWhenNotNull { 172 | downloadAPKPath + getString( 173 | R.string.versionchecklib_download_apkname, 174 | if (apkName != null) apkName else packageName 175 | ) 176 | 177 | } ?: "" 178 | } 179 | 180 | @WorkerThread 181 | private fun startDownloadApk() { 182 | //判断是否缓存并且是否强制重新下载 183 | fun inner() { 184 | BuilderManager.doWhenNotNull { 185 | val downloadPath = downloadFilePath 186 | if (AppUtils.checkAPKIsExists( 187 | applicationContext, 188 | downloadPath, 189 | newestVersionCode 190 | ) && !isForceRedownload 191 | ) { 192 | ALog.e("using cache") 193 | install() 194 | return@doWhenNotNull 195 | } 196 | BuilderManager.checkAndDeleteAPK() 197 | var downloadUrl: String? = downloadUrl 198 | if (downloadUrl == null && versionBundle != null) { 199 | downloadUrl = versionBundle.downloadUrl 200 | } 201 | if (downloadUrl == null) { 202 | AllenVersionChecker.getInstance().cancelAllMission() 203 | throw RuntimeException("you must set a download url for download function using") 204 | } 205 | ALog.e("downloadPath:$downloadPath") 206 | DownloadMangerV2.download( 207 | downloadUrl, 208 | downloadAPKPath, 209 | getString( 210 | R.string.versionchecklib_download_apkname, 211 | if (apkName != null) apkName else packageName 212 | ), 213 | downloadListener 214 | ) 215 | } 216 | } 217 | executors?.submit { inner() } 218 | 219 | 220 | } 221 | 222 | private val downloadListener: DownloadListenerKt = object : DownloadListenerKt { 223 | override fun onCheckerDownloading(progress: Int) { 224 | BuilderManager.doWhenNotNull { 225 | ALog.e("download progress $progress") 226 | if (isServiceAlive) { 227 | if (!isSilentDownload) { 228 | if (isShowNotification) 229 | notificationHelper?.updateNotification(progress) 230 | updateDownloadingDialogProgress(progress) 231 | } 232 | apkDownloadListener?.onDownloading(progress) 233 | } 234 | } 235 | 236 | } 237 | 238 | override fun onCheckerDownloadSuccess(file: File) { 239 | BuilderManager.doWhenNotNull { 240 | if (isServiceAlive) { 241 | if (!isSilentDownload && isShowNotification) notificationHelper?.showDownloadCompleteNotifcation( 242 | file 243 | ) 244 | apkDownloadListener?.onDownloadSuccess(file) 245 | install() 246 | } 247 | } 248 | 249 | } 250 | 251 | 252 | override fun onCheckerDownloadFail() { 253 | BuilderManager.doWhenNotNull { 254 | ALog.e("download failed") 255 | if (!isServiceAlive) return@doWhenNotNull 256 | apkDownloadListener?.onDownloadFail() 257 | if (!isSilentDownload) { 258 | AllenEventBusUtil.sendEventBusStick(AllenEventType.CLOSE_DOWNLOADING_ACTIVITY) 259 | if (isShowDownloadFailDialog) { 260 | showDownloadFailedDialog() 261 | } 262 | if (isShowNotification) 263 | notificationHelper?.showDownloadFailedNotification() 264 | } else { 265 | AllenVersionChecker.getInstance().cancelAllMission() 266 | } 267 | } 268 | 269 | } 270 | 271 | override fun onCheckerStartDownload() { 272 | BuilderManager.doWhenNotNull { 273 | ALog.e("start download apk") 274 | if (!isSilentDownload) { 275 | if (isShowNotification) 276 | notificationHelper?.showNotification() 277 | showDownloadingDialog() 278 | } 279 | } 280 | 281 | } 282 | } 283 | 284 | @Subscribe(threadMode = ThreadMode.MAIN) 285 | fun receiveEvent(commonEvent: CommonEvent<*>) { 286 | when (commonEvent.eventType) { 287 | AllenEventType.START_DOWNLOAD_APK -> startDownloadApk() 288 | AllenEventType.STOP_SERVICE -> { 289 | stopSelf() 290 | EventBus.getDefault().removeStickyEvent(commonEvent) 291 | } 292 | } 293 | } 294 | 295 | // @Subscribe(sticky = true, threadMode = ThreadMode.MAIN) 296 | // public synchronized void onReceiveDownloadBuilder(DownloadBuilder downloadBuilder) { 297 | // builder = downloadBuilder; 298 | // init(); 299 | // EventBus.getDefault().removeStickyEvent(downloadBuilder); 300 | // } 301 | private fun init() { 302 | BuilderManager.doWhenNotNull { 303 | //https://issuetracker.google.com/issues/76112072 304 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && isRunOnForegroundService) { 305 | startForeground( 306 | NotificationHelper.NOTIFICATION_ID, 307 | NotificationHelper.createSimpleNotification(this@VersionService) 308 | ) 309 | Thread.sleep(500) 310 | } 311 | isServiceAlive = true 312 | notificationHelper = NotificationHelper(applicationContext) 313 | executors = Executors.newSingleThreadExecutor() 314 | executors?.submit { onHandleWork() } 315 | } 316 | 317 | } 318 | 319 | 320 | } -------------------------------------------------------------------------------- /library/src/main/res/drawable/progressbar_horizontal.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /library/src/main/res/layout/downloading_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 16 | 20 | 26 | 34 | 35 | -------------------------------------------------------------------------------- /library/src/main/res/values-en/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Commit 3 | Cancel 4 | Retry 5 | Download failed and retry? 6 | download successful,click to install 7 | downloading... 8 | New Update 9 | download progress:%d%%/100%% 10 | download failed,click to retry 11 | %d/100 12 | Download apk needs write permission。 13 | %s.apk 14 | application update service is running 15 | 16 | 17 | -------------------------------------------------------------------------------- /library/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #000000 4 | 5 | -------------------------------------------------------------------------------- /library/src/main/res/values/ids.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /library/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | VersionCheckLib 3 | 确认 4 | 取消 5 | 重试 6 | 下载失败是否重试? 7 | 下载完成,点击安装 8 | 正在下载中... 9 | 检测到新版本 10 | 下载进度:%d%%/100%% 11 | 下载失败,点击重试 12 | %d/100 13 | 下载安装包需要读写文件权限。 14 | %s.apk 15 | 更新服务正在运行 16 | 17 | -------------------------------------------------------------------------------- /library/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /library/src/main/res/xml/versionchecklib_file_paths.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 9 | -------------------------------------------------------------------------------- /sample/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /sample/1_1.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexLiuSheng/CheckVersionLib/23ab03936b0bbd78c447ef8d4d10bfba4243e4cf/sample/1_1.apk -------------------------------------------------------------------------------- /sample/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | //apply plugin: 'me.tatarka.retrolambda' 3 | android { 4 | compileSdkVersion 32 5 | defaultConfig { 6 | applicationId "com.allenliu.sample" 7 | minSdkVersion 21 8 | targetSdkVersion 32 9 | versionCode 1 10 | versionName "1.0" 11 | 12 | 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | compileOptions { 21 | targetCompatibility JavaVersion.VERSION_17 22 | sourceCompatibility JavaVersion.VERSION_17 23 | } 24 | namespace 'com.allenliu.sample' 25 | } 26 | 27 | dependencies { 28 | implementation fileTree(include: ['*.jar'], dir: 'libs') 29 | // compile 'com.android.support:appcompat-v7:25.1.0' 30 | implementation 'androidx.constraintlayout:constraintlayout:2.1.4' 31 | testImplementation 'junit:junit:4.12' 32 | implementation project(':library') 33 | // implementation 'com.github.AlexLiuSheng:CheckVersionLib:2.2.2' 34 | // compile 'com.allenliu.versionchecklib:library:2.0.9' 35 | implementation 'androidx.appcompat:appcompat:1.5.1' 36 | // compile 'com.allenliu.versionchecklib:library:1.7.6' 37 | //compile files('libs/library.jar') 38 | implementation('com.squareup.leakcanary:leakcanary-android:2.12') 39 | } 40 | -------------------------------------------------------------------------------- /sample/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\Eclipse\android-sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /sample/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 13 | 14 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /sample/src/main/java/com/allenliu/sample/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.allenliu.sample; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.view.View; 6 | 7 | import androidx.appcompat.app.AppCompatActivity; 8 | 9 | import com.allenliu.sample.v2.V2Activity; 10 | 11 | public class MainActivity extends AppCompatActivity { 12 | 13 | @Override 14 | protected void onCreate(Bundle savedInstanceState) { 15 | super.onCreate(savedInstanceState); 16 | setContentView(R.layout.activity_main); 17 | } 18 | 19 | public void mainOnClick(View view) { 20 | Intent intent; 21 | switch (view.getId()) { 22 | case R.id.btn_v1: 23 | 24 | break; 25 | case R.id.btn_v2: 26 | intent = new Intent(this, V2Activity.class); 27 | startActivity(intent); 28 | 29 | break; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /sample/src/main/java/com/allenliu/sample/MyApplication.java: -------------------------------------------------------------------------------- 1 | package com.allenliu.sample; 2 | 3 | import android.app.Application; 4 | 5 | 6 | import leakcanary.LeakCanary; 7 | 8 | /** 9 | * Created by allenliu on 2018/1/3. 10 | */ 11 | 12 | public class MyApplication extends Application { 13 | @Override 14 | public void onCreate() { 15 | super.onCreate(); 16 | 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /sample/src/main/java/com/allenliu/sample/v1/BaseDialog.java: -------------------------------------------------------------------------------- 1 | package com.allenliu.sample.v1; 2 | 3 | import android.app.Dialog; 4 | import android.content.Context; 5 | 6 | /** 7 | * Created by Allen Liu on 2017/2/23. 8 | */ 9 | public class BaseDialog extends Dialog { 10 | private int res; 11 | 12 | public BaseDialog(Context context, int theme, int res) { 13 | super(context, theme); 14 | // TODO 自动生成的构造函数存根 15 | setContentView(res); 16 | this.res = res; 17 | setCanceledOnTouchOutside(false); 18 | } 19 | 20 | } -------------------------------------------------------------------------------- /sample/src/main/res/drawable/custom_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexLiuSheng/CheckVersionLib/23ab03936b0bbd78c447ef8d4d10bfba4243e4cf/sample/src/main/res/drawable/custom_bg.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable/shape_corner.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/activity_custom_version_dialog.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/activity_custom_version_dialog_two.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 |