Repository: Ray512512/FastUpdate Branch: master Commit: cfc5c9ffaa1d Files: 48 Total size: 54.4 KB Directory structure: gitextract_b0p0yxwt/ ├── .gitignore ├── .idea/ │ ├── gradle.xml │ ├── misc.xml │ ├── modules.xml │ ├── runConfigurations.xml │ └── vcs.xml ├── README.md ├── UpdateAppUtils/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src/ │ ├── androidTest/ │ │ └── java/ │ │ └── teprinciple/ │ │ └── library/ │ │ └── ExampleInstrumentedTest.java │ ├── main/ │ │ ├── AndroidManifest.xml │ │ ├── java/ │ │ │ ├── customview/ │ │ │ │ └── ConfirmDialog.java │ │ │ ├── feature/ │ │ │ │ └── Callback.java │ │ │ └── util/ │ │ │ ├── DownloadAppUtils.java │ │ │ ├── UpdateAppReceiver.java │ │ │ └── UpdateAppUtils.java │ │ └── res/ │ │ ├── drawable/ │ │ │ └── bg_dialog_confirm.xml │ │ ├── layout/ │ │ │ └── dialog_confirm.xml │ │ └── values/ │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test/ │ └── java/ │ └── teprinciple/ │ └── library/ │ └── ExampleUnitTest.java ├── app/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src/ │ ├── androidTest/ │ │ └── java/ │ │ └── com/ │ │ └── example/ │ │ └── teprinciple/ │ │ └── updateappdemo/ │ │ └── ExampleInstrumentedTest.java │ ├── main/ │ │ ├── AndroidManifest.xml │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ └── teprinciple/ │ │ │ └── updateappdemo/ │ │ │ ├── KotlinDemoActivity.kt │ │ │ └── MainActivity.java │ │ └── res/ │ │ ├── drawable/ │ │ │ └── bg_dialog_confirm.xml │ │ ├── layout/ │ │ │ ├── activity_kotlin_demo.xml │ │ │ ├── activity_main.xml │ │ │ └── activity_start.xml │ │ ├── values/ │ │ │ ├── colors.xml │ │ │ ├── dimens.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ ├── values-w820dp/ │ │ │ └── dimens.xml │ │ └── xml/ │ │ └── file_paths.xml │ └── test/ │ └── java/ │ └── com/ │ └── example/ │ └── teprinciple/ │ └── updateappdemo/ │ └── ExampleUnitTest.java ├── build.gradle ├── gradle/ │ └── wrapper/ │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradle.properties ├── gradlew ├── gradlew.bat └── settings.gradle ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ *.iml .gradle /local.properties /.idea/workspace.xml /.idea/libraries .DS_Store /build /captures .externalNativeBuild ================================================ FILE: .idea/gradle.xml ================================================ ================================================ FILE: .idea/misc.xml ================================================ ================================================ FILE: .idea/modules.xml ================================================ ================================================ FILE: .idea/runConfigurations.xml ================================================ ================================================ FILE: .idea/vcs.xml ================================================ ================================================ FILE: README.md ================================================ # UpdateAppUtils1.4 ### 一行代码,快速实现app在线下载更新
A simple library for Android update app ![](update.gif) ## 集成 compile引入 ``` dependencies { compile 'com.teprinciple:updateapputils:1.4' } ``` ## 使用 更新检测一般放在MainActivity或者启动页上, 在请求服务器版本检测接口获取到versionCode、versionName、最新apkPath后调用。 #### 快速使用 ``` UpdateAppUtils.from(this) .serverVersionCode(2) //服务器versionCode .serverVersionName("2.0") //服务器versionName .apkPath(apkPath) //最新apk下载地址 .update(); ``` #### Kotlin代码调用完全一样 ``` private fun update() { val apkPath:String = "http://issuecdn.baidupcs.com/issue/netdisk/apk/BaiduNetdisk_7.15.1.apk" UpdateAppUtils.from(this) .serverVersionCode(2) .serverVersionName("2.0") .apkPath(apkPath) .update() } ``` #### 更多配置使用 ``` UpdateAppUtils.from(this) .checkBy(UpdateAppUtils.CHECK_BY_VERSION_NAME) //更新检测方式,默认为VersionCode .serverVersionCode(2) .serverVersionName("2.0") .apkPath(apkPath) .showNotification(false) //是否显示下载进度到通知栏,默认为true .updateInfo(info) //更新日志信息 String .downloadBy(UpdateAppUtils.DOWNLOAD_BY_BROWSER) //下载方式:app下载、手机浏览器下载。默认app下载 .isForce(true) //是否强制更新,默认false 强制更新情况下用户不同意更新则不能使用app .update(); ``` #### 说明 ``` 1、UpdateAppUtils提供两种更新判断方式 CHECK_BY_VERSION_CODE:通过versionCode判断,服务器上versionCode > 本地versionCode则执行更新 CHECK_BY_VERSION_NAME:通过versionName判断,服务器上versionName 与 本地versionName不同则更新 2、UpdateAppUtils提供两种下载apk方式 DOWNLOAD_BY_APP:通过App下载 DOWNLOAD_BY_BROWSER:通过手机浏览器下载 ``` #### 关于适配Android6.0、Android7.0 ##### 适配Android7.0 1、注册provider ``` /provider> ``` 2、新建file_paths.xml文件 ``` ``` 可参见demo中的代码 如果你的版本没有适配到Android7.0 为了不进行上述操作,可以直接这样设置: ``` UpdateAppUtils.needFitAndroidN(false) ``` ##### 适配Android6.0 关于6.0适配,请自行在调用API时申请WRITE_EXTERNAL_STORAGE权限,可以参考demo中的代码 #### 更新日志 1.4
使用[filedownloader](https://github.com/lingochamp/FileDownloader)替换DownloadManager,避免部分手机DownLoadManager无效,同时解决了重复下载的问题,且提高了下载速度
增加接口UpdateAppUtils.needFitAndroidN(false),避免不需要适配7.0,也要设置FileProvider

1.3.1
修复部分bug,在demo中加入kotlin调用代码

1.3
增加接口方法 showNotification(false)//是否显示下载进度到通知栏;
updateInfo(info)//更新日志信息;下载前WiFi判断。

1.2
适配Android7.0,并在demo中加入适配6.0和7.0的代码

1.1
适配更多SdkVersion ================================================ FILE: UpdateAppUtils/.gitignore ================================================ /build ================================================ FILE: UpdateAppUtils/build.gradle ================================================ apply plugin: 'com.android.library' android { compileSdkVersion 25 buildToolsVersion "25.0.3" defaultConfig { minSdkVersion 14 targetSdkVersion 25 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { exclude group: 'com.android.support', module: 'support-annotations' }) compile 'com.android.support:appcompat-v7:25.3.1' testCompile 'junit:junit:4.12' compile 'com.liulishuo.filedownloader:library:1.6.8' } apply plugin: 'com.github.dcendents.android-maven' apply plugin: 'com.jfrog.bintray' // This is the library version used when deploying the artifact version = "1.4" def siteUrl = 'https://github.com/teprinciple/UpdateAppDemo' // 项目的主页 def gitUrl = 'https://github.com/teprinciple/UpdateAppDemo.git' // Git仓库的url group = "com.teprinciple" // Maven Group ID for the artifact,一般填你唯一的包名 install { repositories.mavenInstaller { // This generates POM.file_paths with proper parameters pom { project { packaging 'aar' // Add your description here name 'A Simple library for Android update app' url siteUrl // Set your license licenses { license { name 'The Apache Software License, Version 2.0' url 'http://www.apache.org/licenses/LICENSE-2.0.txt' } } developers { developer { id 'teprinciple' //填写的一些基本信息 name 'teprinciple' email 'teprinciple@foxmail.com' } } scm { connection gitUrl developerConnection gitUrl url siteUrl } } } } } task sourcesJar(type: Jar) { from android.sourceSets.main.java.srcDirs classifier = 'sources' } task javadoc(type: Javadoc) { source = android.sourceSets.main.java.srcDirs classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) } task javadocJar(type: Jar, dependsOn: javadoc) { classifier = 'javadoc' from javadoc.destinationDir } artifacts { archives javadocJar archives sourcesJar } Properties properties = new Properties() properties.load(project.rootProject.file('local.properties').newDataInputStream()) bintray { user = properties.getProperty("bintray.user") key = properties.getProperty("bintray.apikey") configurations = ['archives'] pkg { repo = "maven" ////跟上面创建的Maven仓库名字保持一致 name = "UpdateAppUtils" //发布到JCenter上的项目名字 websiteUrl = siteUrl vcsUrl = gitUrl licenses = ["Apache-2.0"] publish = true } } javadoc { //jav doc采用utf-8编码否则会报“GBK的不可映射字符”错误 options{ encoding "UTF-8" charSet 'UTF-8' } } ================================================ FILE: UpdateAppUtils/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # By default, the flags in this file are appended to flags specified # in /Users/teprinciple/Library/Android/sdk/tools/proguard/proguard-android.txt # You can edit the include path and order by changing the proguardFiles # directive in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # Add any project specific keep options here: # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} # Uncomment this to preserve the line number information for # debugging stack traces. #-keepattributes SourceFile,LineNumberTable # If you keep the line number information, uncomment this to # hide the original source file name. #-renamesourcefileattribute SourceFile ================================================ FILE: UpdateAppUtils/src/androidTest/java/teprinciple/library/ExampleInstrumentedTest.java ================================================ package teprinciple.library; import android.content.Context; import android.support.test.InstrumentationRegistry; import android.support.test.runner.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; import static org.junit.Assert.*; /** * Instrumentation test, which will execute on an Android device. * * @see Testing documentation */ @RunWith(AndroidJUnit4.class) public class ExampleInstrumentedTest { @Test public void useAppContext() throws Exception { // Context of the app under test. Context appContext = InstrumentationRegistry.getTargetContext(); assertEquals("teprinciple.library.test", appContext.getPackageName()); } } ================================================ FILE: UpdateAppUtils/src/main/AndroidManifest.xml ================================================ ================================================ FILE: UpdateAppUtils/src/main/java/customview/ConfirmDialog.java ================================================ package customview; import android.app.Dialog; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.widget.TextView; import feature.Callback; import teprinciple.updateapputils.R; /** * Created by Teprinciple on 2016/10/13. */ public class ConfirmDialog extends Dialog { Callback callback; private TextView content; private TextView sureBtn; private TextView cancleBtn; public ConfirmDialog(Context context, Callback callback) { super(context, R.style.CustomDialog); this.callback = callback; setCustomDialog(); } private void setCustomDialog() { View mView = LayoutInflater.from(getContext()).inflate(R.layout.dialog_confirm, null); sureBtn = (TextView)mView.findViewById(R.id.dialog_confirm_sure); cancleBtn = (TextView)mView.findViewById(R.id.dialog_confirm_cancle); content = (TextView) mView.findViewById(R.id.dialog_confirm_title); sureBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { callback.callback(1); ConfirmDialog.this.cancel(); } }); cancleBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { callback.callback(0); ConfirmDialog.this.cancel(); } }); super.setContentView(mView); } public ConfirmDialog setContent(String s){ content.setText(s); return this; } } ================================================ FILE: UpdateAppUtils/src/main/java/feature/Callback.java ================================================ package feature; /** * Created by sanmu on 2016/10/13 0013. */ public interface Callback { public void callback(int position); } ================================================ FILE: UpdateAppUtils/src/main/java/util/DownloadAppUtils.java ================================================ package util; import android.app.AlertDialog; import android.app.DownloadManager; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.net.Uri; import android.os.Build; import android.os.Environment; import android.provider.Settings; import android.support.v4.content.FileProvider; import android.text.TextUtils; import android.util.Log; import android.widget.Toast; import com.liulishuo.filedownloader.BaseDownloadTask; import com.liulishuo.filedownloader.FileDownloadLargeFileListener; import com.liulishuo.filedownloader.FileDownloader; import java.io.File; /** * Created by Teprinciple on 2016/12/13. */ class DownloadAppUtils { private static final String TAG = DownloadAppUtils.class.getSimpleName(); public static long downloadUpdateApkId = -1;//下载更新Apk 下载任务对应的Id public static String downloadUpdateApkFilePath;//下载更新Apk 文件路径 /** * 通过浏览器下载APK包 * @param context * @param url */ public static void downloadForWebView(Context context, String url) { Uri uri = Uri.parse(url); Intent intent = new Intent(Intent.ACTION_VIEW, uri); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intent); } public static void download(final Context context, String url,final String serverVersionName) { String packageName = context.getPackageName(); String filePath = null; if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {//外部存储卡 filePath = Environment.getExternalStorageDirectory().getAbsolutePath(); } else { Log.i(TAG, "没有SD卡"); return; } String apkLocalPath= filePath + File.separator + packageName + "_"+serverVersionName+".apk"; downloadUpdateApkFilePath = apkLocalPath; FileDownloader.setup(context); FileDownloader.getImpl().create(url) .setPath(apkLocalPath) .setListener(new FileDownloadLargeFileListener() { @Override protected void pending(BaseDownloadTask task, long soFarBytes, long totalBytes) { } @Override protected void progress(BaseDownloadTask task, long soFarBytes, long totalBytes) { send(context, (int) (soFarBytes*100.0/totalBytes),serverVersionName); } @Override protected void paused(BaseDownloadTask task, long soFarBytes, long totalBytes) { } @Override protected void completed(BaseDownloadTask task) { send(context,100,serverVersionName); } @Override protected void error(BaseDownloadTask task, Throwable e) { Toast.makeText(context, "下载出错", Toast.LENGTH_SHORT).show(); } @Override protected void warn(BaseDownloadTask task) { } }).start(); } private static void send(Context context,int progress,String serverVersionName) { Intent intent = new Intent("teprinciple.update"); intent.putExtra("progress",progress); intent.putExtra("title",serverVersionName); context.sendBroadcast(intent); } } ================================================ FILE: UpdateAppUtils/src/main/java/util/UpdateAppReceiver.java ================================================ package util; import android.app.Notification; import android.app.NotificationManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Build; import android.support.v4.app.NotificationCompat; import android.support.v4.content.FileProvider; import java.io.File; /** * Created by Teprinciple on 2017/11/3. */ public class UpdateAppReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { int notifyId = 1; int progress = intent.getIntExtra("progress", 0); String title = intent.getStringExtra("title"); NotificationManager nm = null; if (UpdateAppUtils.showNotification){ NotificationCompat.Builder builder = new NotificationCompat.Builder(context); builder.setContentTitle("正在下载 "+title); builder.setSmallIcon(android.R.mipmap.sym_def_app_icon); builder.setProgress(100,progress,false); Notification notification = builder.build(); nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); nm.notify(notifyId,notification); } if (progress == 100){ if (nm!=null)nm.cancel(notifyId); if (DownloadAppUtils.downloadUpdateApkFilePath != null) { Intent i = new Intent(Intent.ACTION_VIEW); File apkFile = new File(DownloadAppUtils.downloadUpdateApkFilePath); if ( UpdateAppUtils.needFitAndroidN && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); Uri contentUri = FileProvider.getUriForFile( context, context.getPackageName() + ".fileprovider", apkFile); i.setDataAndType(contentUri, "application/vnd.android.package-archive"); } else { i.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive"); } i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(i); } } } } ================================================ FILE: UpdateAppUtils/src/main/java/util/UpdateAppUtils.java ================================================ package util; import android.app.Activity; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.text.TextUtils; import android.util.Log; import customview.ConfirmDialog; import feature.Callback; /** * Created by Teprinciple on 2016/11/15. */ public class UpdateAppUtils { private final String TAG = "UpdateAppUtils"; public static final int CHECK_BY_VERSION_NAME = 1001; public static final int CHECK_BY_VERSION_CODE = 1002; public static final int DOWNLOAD_BY_APP = 1003; public static final int DOWNLOAD_BY_BROWSER = 1004; private Activity activity; private int checkBy = CHECK_BY_VERSION_CODE; private int downloadBy = DOWNLOAD_BY_APP; private int serverVersionCode = 0; private String apkPath=""; private String serverVersionName=""; private boolean isForce = false; //是否强制更新 private int localVersionCode = 0; private String localVersionName=""; public static boolean needFitAndroidN = true; //提供给 整个工程不需要适配到7.0的项目 置为false public static boolean showNotification = true; private String updateInfo = ""; public UpdateAppUtils needFitAndroidN(boolean needFitAndroidN) { UpdateAppUtils.needFitAndroidN = needFitAndroidN; return this; } private UpdateAppUtils(Activity activity) { this.activity = activity; getAPPLocalVersion(activity); } public static UpdateAppUtils from(Activity activity){ return new UpdateAppUtils(activity); } public UpdateAppUtils checkBy(int checkBy){ this.checkBy = checkBy; return this; } public UpdateAppUtils apkPath(String apkPath){ this.apkPath = apkPath; return this; } public UpdateAppUtils downloadBy(int downloadBy){ this.downloadBy = downloadBy; return this; } public UpdateAppUtils showNotification(boolean showNotification){ this.showNotification = showNotification; return this; } public UpdateAppUtils updateInfo(String updateInfo){ this.updateInfo = updateInfo; return this; } public UpdateAppUtils serverVersionCode(int serverVersionCode){ this.serverVersionCode = serverVersionCode; return this; } public UpdateAppUtils serverVersionName(String serverVersionName){ this.serverVersionName = serverVersionName; return this; } public UpdateAppUtils isForce(boolean isForce){ this.isForce = isForce; return this; } //获取apk的版本号 currentVersionCode private void getAPPLocalVersion(Context ctx) { PackageManager manager = ctx.getPackageManager(); try { PackageInfo info = manager.getPackageInfo(ctx.getPackageName(), 0); localVersionName = info.versionName; // 版本名 localVersionCode = info.versionCode; // 版本号 } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } } public void update(){ switch (checkBy){ case CHECK_BY_VERSION_CODE: if (serverVersionCode >localVersionCode){ toUpdate(); }else { Log.i(TAG,"当前版本是最新版本"+serverVersionCode+"/"+serverVersionName); } break; case CHECK_BY_VERSION_NAME: if (!serverVersionName.equals(localVersionName)){ toUpdate(); }else { Log.i(TAG,"当前版本是最新版本"+serverVersionCode+"/"+serverVersionName); } break; } } private void toUpdate() { realUpdate(); } private void realUpdate() { ConfirmDialog dialog = new ConfirmDialog(activity, new Callback() { @Override public void callback(int position) { switch (position){ case 0: //cancle if (isForce)System.exit(0); break; case 1: //sure if (downloadBy == DOWNLOAD_BY_APP) { if (isWifiConnected(activity)){ // DownloadAppUtils.downloadForAutoInstall(activity, apkPath, "demo.apk", serverVersionName); DownloadAppUtils.download(activity, apkPath, serverVersionName); }else { new ConfirmDialog(activity, new Callback() { @Override public void callback(int position) { if (position==1){ DownloadAppUtils.download(activity, apkPath, serverVersionName); //DownloadAppUtils.downloadForAutoInstall(activity, apkPath, "demo.apk", serverVersionName); }else { if (isForce)activity.finish(); } } }).setContent("目前手机不是WiFi状态\n确认是否继续下载更新?").show(); } }else if (downloadBy == DOWNLOAD_BY_BROWSER){ DownloadAppUtils.downloadForWebView(activity,apkPath); } break; } } }); String content = "发现新版本:"+serverVersionName+"\n是否下载更新?"; if (!TextUtils.isEmpty(updateInfo)){ content = "发现新版本:"+serverVersionName+"是否下载更新?\n\n"+updateInfo; } dialog .setContent(content); dialog.setCancelable(false); dialog.show(); } /** * 检测wifi是否连接 */ public static boolean isWifiConnected(Context context) { ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); if (cm != null) { NetworkInfo networkInfo = cm.getActiveNetworkInfo(); if (networkInfo != null && networkInfo.getType() == ConnectivityManager.TYPE_WIFI) { return true; } } return false; } } ================================================ FILE: UpdateAppUtils/src/main/res/drawable/bg_dialog_confirm.xml ================================================ ================================================ FILE: UpdateAppUtils/src/main/res/layout/dialog_confirm.xml ================================================ ================================================ FILE: UpdateAppUtils/src/main/res/values/colors.xml ================================================ #3F51B5 #303F9F #FF4081 #0076FF #333333 ================================================ FILE: UpdateAppUtils/src/main/res/values/strings.xml ================================================ Library 取消 确认 ================================================ FILE: UpdateAppUtils/src/main/res/values/styles.xml ================================================ ================================================ FILE: UpdateAppUtils/src/test/java/teprinciple/library/ExampleUnitTest.java ================================================ package teprinciple.library; import org.junit.Test; import static org.junit.Assert.*; /** * Example local unit test, which will execute on the development machine (host). * * @see Testing documentation */ public class ExampleUnitTest { @Test public void addition_isCorrect() throws Exception { assertEquals(4, 2 + 2); } } ================================================ FILE: app/.gitignore ================================================ /build ================================================ FILE: app/build.gradle ================================================ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' android { compileSdkVersion 25 buildToolsVersion "25.0.2" defaultConfig { applicationId "com.example.teprinciple.updateappdemo" minSdkVersion 19 targetSdkVersion 23 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } lintOptions { abortOnError false } } dependencies { compile fileTree(include: ['*.jar'], dir: 'libs') androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { exclude group: 'com.android.support', module: 'support-annotations' }) compile project(':updateapputils') compile 'com.android.support:appcompat-v7:25.1.0' compile 'com.android.support.constraint:constraint-layout:1.0.2' testCompile 'junit:junit:4.12' compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" } repositories { mavenCentral() } ================================================ FILE: app/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # By default, the flags in this file are appended to flags specified # in C:\Users\Teprinciple\AppData\Local\Android\Sdk/tools/proguard/proguard-android.txt # You can edit the include path and order by changing the proguardFiles # directive in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # Add any project specific keep options here: # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} ================================================ FILE: app/src/androidTest/java/com/example/teprinciple/updateappdemo/ExampleInstrumentedTest.java ================================================ package com.example.teprinciple.updateappdemo; import android.content.Context; import android.support.test.InstrumentationRegistry; import android.support.test.runner.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; import static org.junit.Assert.*; /** * Instrumentation test, which will execute on an Android device. * * @see Testing documentation */ @RunWith(AndroidJUnit4.class) public class ExampleInstrumentedTest { @Test public void useAppContext() throws Exception { // Context of the app under test. Context appContext = InstrumentationRegistry.getTargetContext(); assertEquals("com.example.teprinciple.updateappdemo", appContext.getPackageName()); } } ================================================ FILE: app/src/main/AndroidManifest.xml ================================================ ================================================ FILE: app/src/main/java/com/example/teprinciple/updateappdemo/KotlinDemoActivity.kt ================================================ package com.example.teprinciple.updateappdemo import android.support.v7.app.AppCompatActivity import android.os.Bundle import util.UpdateAppUtils class KotlinDemoActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_kotlin_demo) findViewById(R.id.kotlin_btn).setOnClickListener { update() } } private fun update() { val apkPath:String = "http://issuecdn.baidupcs.com/issue/netdisk/apk/BaiduNetdisk_7.15.1.apk" UpdateAppUtils.from(this) .serverVersionCode(2) .serverVersionName("2.0") .apkPath(apkPath) .update() } } ================================================ FILE: app/src/main/java/com/example/teprinciple/updateappdemo/MainActivity.java ================================================ package com.example.teprinciple.updateappdemo; import android.Manifest; import android.content.Intent; import android.content.pm.PackageManager; import android.net.Uri; import android.os.Build; import android.provider.Settings; import android.support.annotation.NonNull; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Toast; import customview.ConfirmDialog; import feature.Callback; import util.UpdateAppUtils; public class MainActivity extends AppCompatActivity { //服务器apk path,这里放了百度云盘的apk 作为测试 String apkPath = "http://issuecdn.baidupcs.com/issue/netdisk/apk/BaiduNetdisk_7.15.1.apk"; private int code = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void updateApp(View view) { checkAndUpdate(1); } public void downloadByWeb(View view) { checkAndUpdate(2); } public void forceUpdate(View view) { checkAndUpdate(3); } public void checkByName(View view) { checkAndUpdate(4); } public void kotlin(View view) { checkAndUpdate(5); } private void checkAndUpdate(int code) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { realUpdate(code); } else { if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { realUpdate(code); } else {//申请权限 ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1); } } } private void realUpdate(int code) { this.code = code; switch (code) { case 1: updat1(); break; case 2: update2(); break; case 3: update3(); break; case 4: update4(); break; case 5: startActivity(new Intent(this,KotlinDemoActivity.class)); break; } } //基本更新 private void updat1() { UpdateAppUtils.from(this) .serverVersionCode(2) .serverVersionName("2.0") .apkPath(apkPath) .updateInfo("1.修复若干bug\n2.美化部分页面\n3.增加微信支付方式") // .showNotification(false) // .needFitAndroidN(false) .update(); } //通过浏览器下载 private void update2() { UpdateAppUtils.from(this) .serverVersionCode(2) .serverVersionName("2.0") .apkPath(apkPath) .downloadBy(UpdateAppUtils.DOWNLOAD_BY_BROWSER) .update(); } //强制更新 private void update3() { UpdateAppUtils.from(this) .serverVersionCode(2) .serverVersionName("2.0") .apkPath(apkPath) .isForce(true) .update(); } //根据versionName判断跟新 private void update4() { UpdateAppUtils.from(this) .checkBy(UpdateAppUtils.CHECK_BY_VERSION_NAME) .serverVersionName("2.0") .serverVersionCode(2) .apkPath(apkPath) .downloadBy(UpdateAppUtils.DOWNLOAD_BY_BROWSER) .isForce(true) .update(); } //权限请求结果 @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); switch (requestCode) { case 1: if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { realUpdate(code); } else { new ConfirmDialog(this, new Callback() { @Override public void callback(int position) { if (position==1){ Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); intent.setData(Uri.parse("package:" + getPackageName())); // 根据包名打开对应的设置界面 startActivity(intent); } } }).setContent("暂无读写SD卡权限\n是否前往设置?").show(); } break; } } } ================================================ FILE: app/src/main/res/drawable/bg_dialog_confirm.xml ================================================ ================================================ FILE: app/src/main/res/layout/activity_kotlin_demo.xml ================================================