diff --git a/.classpath b/.classpath
deleted file mode 100644
index 17aadf8..0000000
--- a/.classpath
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/.gitignore b/.gitignore
index d784722..e3e64c8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -25,4 +25,10 @@ proguard/
# Log Files
*.log
-.settings/
\ No newline at end of file
+.settings/
+
+# Intellij project files
+*.iml
+*.ipr
+*.iws
+.idea/
\ No newline at end of file
diff --git a/.project b/.project
deleted file mode 100644
index eb78f6b..0000000
--- a/.project
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
- UpdateHelper
-
-
-
-
-
- com.android.ide.eclipse.adt.ResourceManagerBuilder
-
-
-
-
- com.android.ide.eclipse.adt.PreCompilerBuilder
-
-
-
-
- org.eclipse.jdt.core.javabuilder
-
-
-
-
- com.android.ide.eclipse.adt.ApkBuilder
-
-
-
-
-
- com.android.ide.eclipse.adt.AndroidNature
- org.eclipse.jdt.core.javanature
-
-
diff --git a/README.md b/README.md
index 568fdf9..f7edff1 100644
--- a/README.md
+++ b/README.md
@@ -1,25 +1,28 @@
-#UpdateHelper
+# UpdateHelper
+[](h) []() []()
-##UpdateHelper是什么?
-UpdateHelper是一个Android Library项目。
-##UpdateHelper是干什么的?
-这个项目是为了简化Android App的迭代升级开发,任何一个项目只要引入这个library便集成了在线检查新版本的功能以及下载APK功能。
-##UpdateHelper要怎么使用?
-**1.首先服务器端需要提供一个接口,返回json数据格式如下:**
+
+## UpdateHelper 是什么?
+UpdateHelper 是一个只需一行代码即可实现APP在线升级的 Android Library。
+## UpdateHelper 是干什么的?
+这个项目是为了简化 Android APP 的迭代升级开发,任何一个项目只要引入这个 library 便集成了在线检查新版本的功能以及下载 APK 功能。
+## UpdateHelper 要怎么使用?
+**1.首先服务器端需要提供一个接口,返回 JSON 数据格式如下:**
```Java
{
"appName": "TestUpdate",
"versionCode": "1",
"versionName": "1.0",
- "apkUrl": "http://java.linuxlearn.net/shelwee/Finances.apk",
+ "apkUrl": "http://www.shelwee.com/404.apk",
"changeLog":"1.修复xxx Bug;\n2.更新UI界面.",
- "updateTips": "更新提示"
+ "updateTips": "更新提示" ,
+ "forceUpgrade": true //当有新版本时,APP 将会自动下载安装包
}
```
**2.客户端操作如下:**
```Java
UpdateHelper updateHelper = new UpdateHelper.Builder(this)
- .checkUrl("http://localhost/check.jsp")
+ .checkUrl("http://www.shelwee.com/check.jsp")
.isAutoInstall(false) //设置为false需在下载完手动点击安装;默认值为true,下载后自动安装。
.build();
updateHelper.check();
@@ -59,34 +62,42 @@ UpdateHelper是一个Android Library项目。
});
*/
```
-###UpdateHelper需要哪些权限?
+### UpdateHelper 需要哪些权限?
```java
-
-
-
+
+
+
```
-###UpdateHelper原理是什么?
-UpdateHelper通过接口返回的数据versionCode,与当前app的versionCode匹配,如果版本号比当前app的versionCode大,则存在新版本,弹出更新提示对话框;否则提示当前版本是最新版。
-Note:当遇到网络中断或阻塞等问题时,处理方式也为提示当前版本是最新版。
+### UpdateHelper 原理是什么?
+UpdateHelper 通过接口返回的数据 versionCode,与当前 APP 的 versionCode 匹配,如果版本号比当前 APP 的 versionCode 大,则存在新版本,弹出更新提示对话框;否则提示当前版本是最新版。
+
+**注:当遇到网络中断或阻塞等问题时,处理方式也为提示当前版本是最新版。**
-###截图
+### UpdateHelper 运行截图



-###License
->Copyright 2014 ShelWee(http://www.shelwee.com)
-
->Licensed under the Apache License, Version 2.0 (the "License");
->you may not use this file except in compliance with the License.
->You may obtain a copy of the License at
+### Change Logs
+---
+Version 1.0 - Released date: 1-8-2017
+```
+- 从 ADT 转换成 Android Studio 项目
+- 优化部分代码实现逻辑
+- 网络部分全部改为 HttpURLConnection 实现
+- 修复下载过程与通知栏进度条卡顿情况
+- 提示文字全部提取到 strings.xml,方便国际化操作
+- 新增强制升级功能,通过后台接口 JSON 返回 forceUpgrade:true/false
+```
+Version 0.2 - Released date: 3-26-2016
+```
+- 新增校验文件是否已下载
+```
-> http://www.apache.org/licenses/LICENSE-2.0
+Version 0.1 - Released date: 5-8-2014
+```
+- 发布UpdateHelper第一个版本
->Unless required by applicable law or agreed to in writing, software
->distributed under the License is distributed on an "AS IS" BASIS,
->WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
->See the License for the specific language governing permissions and
->limitations under the License.
+```
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000..c0f51c2
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,22 @@
+apply plugin: 'com.android.library'
+
+android {
+ compileSdkVersion 23
+ buildToolsVersion "23.0.2"
+
+ defaultConfig {
+ minSdkVersion 14
+ targetSdkVersion 23
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
+ }
+ }
+}
+
+dependencies {
+ compile 'com.android.support:appcompat-v7:23.4.0'
+}
diff --git a/libs/android-support-v4.jar b/libs/android-support-v4.jar
deleted file mode 100644
index 96644ed..0000000
Binary files a/libs/android-support-v4.jar and /dev/null differ
diff --git a/proguard-project.txt b/proguard-project.txt
deleted file mode 100644
index f2fe155..0000000
--- a/proguard-project.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-# To enable ProGuard in your project, edit project.properties
-# to define the proguard.config property as described in that file.
-#
-# Add project specific ProGuard rules here.
-# By default, the flags in this file are appended to flags specified
-# in ${sdk.dir}/tools/proguard/proguard-android.txt
-# You can edit the include path and order by changing the ProGuard
-# include property in project.properties.
-#
-# 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 *;
-#}
diff --git a/project.properties b/project.properties
deleted file mode 100644
index 03d0617..0000000
--- a/project.properties
+++ /dev/null
@@ -1,15 +0,0 @@
-# This file is automatically generated by Android Tools.
-# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
-#
-# This file must be checked in Version Control Systems.
-#
-# To customize properties used by the Ant build system edit
-# "ant.properties", and override values to adapt the script to your
-# project structure.
-#
-# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
-#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
-
-# Project target.
-target=android-10
-android.library=true
diff --git a/res/drawable-hdpi/ic_launcher.png b/res/drawable-hdpi/ic_launcher.png
deleted file mode 100644
index 96a442e..0000000
Binary files a/res/drawable-hdpi/ic_launcher.png and /dev/null differ
diff --git a/res/drawable-mdpi/ic_launcher.png b/res/drawable-mdpi/ic_launcher.png
deleted file mode 100644
index 359047d..0000000
Binary files a/res/drawable-mdpi/ic_launcher.png and /dev/null differ
diff --git a/res/drawable-xhdpi/ic_launcher.png b/res/drawable-xhdpi/ic_launcher.png
deleted file mode 100644
index 71c6d76..0000000
Binary files a/res/drawable-xhdpi/ic_launcher.png and /dev/null differ
diff --git a/res/values/strings.xml b/res/values/strings.xml
deleted file mode 100644
index ea98f1a..0000000
--- a/res/values/strings.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
- android-updater
-
-
diff --git a/src/com/shelwee/update/UpdateHelper.java b/src/com/shelwee/update/UpdateHelper.java
deleted file mode 100644
index eba8f34..0000000
--- a/src/com/shelwee/update/UpdateHelper.java
+++ /dev/null
@@ -1,466 +0,0 @@
-package com.shelwee.update;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.HashMap;
-
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpResponse;
-import org.apache.http.HttpStatus;
-import org.apache.http.client.HttpClient;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.impl.client.DefaultHttpClient;
-
-import android.app.AlertDialog;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.Environment;
-import android.os.Handler;
-import android.os.Message;
-import android.support.v4.app.NotificationCompat;
-import android.util.Log;
-import android.widget.Toast;
-
-import com.shelwee.update.listener.OnUpdateListener;
-import com.shelwee.update.pojo.UpdateInfo;
-import com.shelwee.update.utils.HttpRequest;
-import com.shelwee.update.utils.JSONHandler;
-import com.shelwee.update.utils.NetWorkUtils;
-import com.shelwee.update.utils.URLUtils;
-
-/**
- * Created by ShelWee on 14-5-8.
- * Usage:
- *
- *
- * UpdateManager updateManager = new UpdateManager.Builder(this)
- * .checkUrl("http://localhost/examples/version.jsp")
- * .isAutoInstall(false)
- * .build();
- * updateManager.check();
- *
- *
- * @author ShelWee(http://www.shelwee.com)
- * @version 0.1 beta
- */
-public class UpdateHelper {
-
- private Context mContext;
- private String checkUrl;
- private boolean isAutoInstall;
- private boolean isHintVersion;
- private OnUpdateListener updateListener;
- private NotificationManager notificationManager;
- private NotificationCompat.Builder ntfBuilder;
-
- private static final int UPDATE_NOTIFICATION_PROGRESS = 0x1;
- private static final int COMPLETE_DOWNLOAD_APK = 0x2;
- private static final int DOWNLOAD_NOTIFICATION_ID = 0x3;
- private static final String PATH = Environment
- .getExternalStorageDirectory().getPath();
- private static final String SUFFIX = ".apk";
- private static final String APK_PATH = "APK_PATH";
- private static final String APP_NAME = "APP_NAME";
- private SharedPreferences preferences_update;
-
- private HashMap cache = new HashMap();
-
- private Handler handler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- super.handleMessage(msg);
- switch (msg.what) {
- case UPDATE_NOTIFICATION_PROGRESS:
- showDownloadNotificationUI((UpdateInfo) msg.obj, msg.arg1);
- break;
- case COMPLETE_DOWNLOAD_APK:
- if (UpdateHelper.this.isAutoInstall) {
- installApk(Uri.parse("file://" + cache.get(APK_PATH)));
- } else {
- if (ntfBuilder == null) {
- ntfBuilder = new NotificationCompat.Builder(mContext);
- }
- ntfBuilder.setSmallIcon(mContext.getApplicationInfo().icon)
- .setContentTitle(cache.get(APP_NAME))
- .setContentText("下载完成,点击安装").setTicker("任务下载完成");
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setDataAndType(
- Uri.parse("file://" + cache.get(APK_PATH)),
- "application/vnd.android.package-archive");
- PendingIntent pendingIntent = PendingIntent.getActivity(
- mContext, 0, intent, 0);
- ntfBuilder.setContentIntent(pendingIntent);
- if (notificationManager == null) {
- notificationManager = (NotificationManager) mContext
- .getSystemService(Context.NOTIFICATION_SERVICE);
- }
- notificationManager.notify(DOWNLOAD_NOTIFICATION_ID,
- ntfBuilder.build());
- }
- break;
- }
- }
-
- };
-
- private UpdateHelper(Builder builder) {
- this.mContext = builder.context;
- this.checkUrl = builder.checkUrl;
- this.isAutoInstall = builder.isAutoInstall;
- this.isHintVersion = builder.isHintNewVersion;
- preferences_update = mContext.getSharedPreferences("Updater",
- Context.MODE_PRIVATE);
- }
-
- /**
- * 检查app是否有新版本,check之前先Builer所需参数
- */
- public void check() {
- check(null);
- }
-
- public void check(OnUpdateListener listener) {
- if (listener != null) {
- this.updateListener = listener;
- }
- if (mContext == null) {
- Log.e("NullPointerException", "The context must not be null.");
- return;
- }
- AsyncCheck asyncCheck = new AsyncCheck();
- asyncCheck.execute(checkUrl);
- }
-
- /**
- * 2014-10-27新增流量提示框,当网络为数据流量方式时,下载就会弹出此对话框提示
- * @param updateInfo
- */
- private void showNetDialog(final UpdateInfo updateInfo){
- AlertDialog.Builder netBuilder = new AlertDialog.Builder(mContext);
- netBuilder.setTitle("下载提示");
- netBuilder.setMessage("您在目前的网络环境下继续下载将可能会消耗手机流量,请确认是否继续下载?");
- netBuilder.setNegativeButton("取消下载",
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- dialog.dismiss();
- }
- });
- netBuilder.setPositiveButton("继续下载",
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- dialog.dismiss();
- AsyncDownLoad asyncDownLoad = new AsyncDownLoad();
- asyncDownLoad.execute(updateInfo);
- }
- });
- AlertDialog netDialog = netBuilder.create();
- netDialog.setCanceledOnTouchOutside(false);
- netDialog.show();
- }
-
- /**
- * 弹出提示更新窗口
- *
- * @param updateInfo
- */
- private void showUpdateUI(final UpdateInfo updateInfo) {
- AlertDialog.Builder upDialogBuilder = new AlertDialog.Builder(mContext);
- upDialogBuilder.setTitle(updateInfo.getUpdateTips());
- upDialogBuilder.setMessage(updateInfo.getChangeLog());
- upDialogBuilder.setNegativeButton("下次再说",
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- dialog.dismiss();
- }
- });
- upDialogBuilder.setPositiveButton("下载",
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- dialog.dismiss();
- NetWorkUtils netWorkUtils = new NetWorkUtils(mContext);
- int type = netWorkUtils.getNetType();
- if (type != 1) {
- showNetDialog(updateInfo);
- }else {
- AsyncDownLoad asyncDownLoad = new AsyncDownLoad();
- asyncDownLoad.execute(updateInfo);
- }
- }
- });
- AlertDialog updateDialog = upDialogBuilder.create();
- updateDialog.setCanceledOnTouchOutside(false);
- updateDialog.show();
- }
-
- /**
- * 通知栏弹出下载提示进度
- *
- * @param updateInfo
- * @param progress
- */
- private void showDownloadNotificationUI(UpdateInfo updateInfo,
- final int progress) {
- if (mContext != null) {
- String contentText = new StringBuffer().append(progress)
- .append("%").toString();
- PendingIntent contentIntent = PendingIntent.getActivity(mContext,
- 0, new Intent(), PendingIntent.FLAG_CANCEL_CURRENT);
- if (notificationManager == null) {
- notificationManager = (NotificationManager) mContext
- .getSystemService(Context.NOTIFICATION_SERVICE);
- }
- if (ntfBuilder == null) {
- ntfBuilder = new NotificationCompat.Builder(mContext)
- .setSmallIcon(mContext.getApplicationInfo().icon)
- .setTicker("开始下载...")
- .setContentTitle(updateInfo.getAppName())
- .setContentIntent(contentIntent);
- }
- ntfBuilder.setContentText(contentText);
- ntfBuilder.setProgress(100, progress, false);
- notificationManager.notify(DOWNLOAD_NOTIFICATION_ID,
- ntfBuilder.build());
- }
- }
-
- /**
- * 获取当前app版本
- *
- * @return
- * @throws android.content.pm.PackageManager.NameNotFoundException
- */
- private PackageInfo getPackageInfo() {
- PackageInfo pinfo = null;
- if (mContext != null) {
- try {
- pinfo = mContext.getPackageManager().getPackageInfo(
- mContext.getPackageName(), 0);
- } catch (PackageManager.NameNotFoundException e) {
- e.printStackTrace();
- }
- }
- return pinfo;
- }
-
- /**
- * 检查更新任务
- */
- private class AsyncCheck extends AsyncTask {
- @Override
- protected void onPreExecute() {
- super.onPreExecute();
- if (UpdateHelper.this.updateListener != null) {
- UpdateHelper.this.updateListener.onStartCheck();
- }
- }
-
- @Override
- protected UpdateInfo doInBackground(String... params) {
- UpdateInfo updateInfo = null;
- if (params.length == 0) {
- Log.e("NullPointerException",
- " Url parameter must not be null.");
- return null;
- }
- String url = params[0];
- if (!URLUtils.isNetworkUrl(url)) {
- Log.e("IllegalArgumentException", "The URL is invalid.");
- return null;
- }
- try {
- updateInfo = JSONHandler.toUpdateInfo(HttpRequest.get(url));
- } catch (Exception e) {
- e.printStackTrace();
- return null;
- }
- return updateInfo;
- }
-
- @Override
- protected void onPostExecute(UpdateInfo updateInfo) {
- super.onPostExecute(updateInfo);
- SharedPreferences.Editor editor = preferences_update.edit();
- if (mContext != null && updateInfo != null) {
- if (Integer.parseInt(updateInfo.getVersionCode()) > getPackageInfo().versionCode) {
- showUpdateUI(updateInfo);
- editor.putBoolean("hasNewVersion", true);
- editor.putString("lastestVersionCode",
- updateInfo.getVersionCode());
- editor.putString("lastestVersionName",
- updateInfo.getVersionName());
- } else {
- if (isHintVersion) {
- Toast.makeText(mContext, "当前已是最新版", Toast.LENGTH_LONG).show();
- }
- editor.putBoolean("hasNewVersion", false);
- }
- } else {
- if (isHintVersion) {
- Toast.makeText(mContext, "当前已是最新版", Toast.LENGTH_LONG).show();
- }
- }
- editor.putString("currentVersionCode", getPackageInfo().versionCode
- + "");
- editor.putString("currentVersionName", getPackageInfo().versionName);
- editor.commit();
- if (UpdateHelper.this.updateListener != null) {
- UpdateHelper.this.updateListener.onFinishCheck(updateInfo);
- }
- }
- }
-
- /**
- * 异步下载app任务
- */
- private class AsyncDownLoad extends AsyncTask {
- @Override
- protected Boolean doInBackground(UpdateInfo... params) {
- HttpClient httpClient = new DefaultHttpClient();
- HttpGet httpGet = new HttpGet(params[0].getApkUrl());
- try {
- HttpResponse response = httpClient.execute(httpGet);
- if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
- Log.e("IllegalArgumentException", "APK路径出错,请检查服务端配置接口。");
- return false;
- } else {
- HttpEntity entity = response.getEntity();
- InputStream inputStream = entity.getContent();
- long total = entity.getContentLength();
- String apkName = params[0].getAppName()
- + params[0].getVersionName() + SUFFIX;
- cache.put(APP_NAME, params[0].getAppName());
- cache.put(APK_PATH,
- PATH + File.separator + params[0].getAppName()
- + File.separator + apkName);
- File savePath = new File(PATH + File.separator
- + params[0].getAppName());
- if (!savePath.exists())
- savePath.mkdirs();
- File apkFile = new File(savePath, apkName);
- if (apkFile.exists()) {
- return true;
- }
- FileOutputStream fos = new FileOutputStream(apkFile);
- byte[] buf = new byte[1024];
- int count = 0;
- int length = -1;
- while ((length = inputStream.read(buf)) != -1) {
- fos.write(buf, 0, length);
- count += length;
- int progress = (int) ((count / (float) total) * 100);
- if (progress % 5 == 0) {
- handler.obtainMessage(UPDATE_NOTIFICATION_PROGRESS,
- progress, -1, params[0]).sendToTarget();
- }
- if (UpdateHelper.this.updateListener != null) {
- UpdateHelper.this.updateListener
- .onDownloading(progress);
- }
- }
- inputStream.close();
- fos.close();
- }
-
- } catch (IOException e) {
- e.printStackTrace();
- return false;
- }
- return true;
- }
-
- @Override
- protected void onPostExecute(Boolean flag) {
- if (flag) {
- handler.obtainMessage(COMPLETE_DOWNLOAD_APK).sendToTarget();
- if (UpdateHelper.this.updateListener != null) {
- UpdateHelper.this.updateListener.onFinshDownload();
- }
- } else {
- Log.e("Error", "下载失败。");
- }
- }
- }
-
- public static class Builder {
- private Context context;
- private String checkUrl;
- private boolean isAutoInstall = true;
- private boolean isHintNewVersion = true;
-
- public Builder(Context ctx) {
- this.context = ctx;
- }
-
- /**
- * 检查是否有新版本App的URL接口路径
- *
- * @param checkUrl
- * @return
- */
- public Builder checkUrl(String checkUrl) {
- this.checkUrl = checkUrl;
- return this;
- }
-
- /**
- * 是否需要自动安装, 不设置默认自动安装
- *
- * @param isAuto
- * true下载完成后自动安装,false下载完成后需在通知栏手动点击安装
- * @return
- */
- public Builder isAutoInstall(boolean isAuto) {
- this.isAutoInstall = isAuto;
- return this;
- }
-
- /**
- * 当没有新版本时,是否Toast提示
- * @param isHint
- * @return true提示,false不提示
- */
- public Builder isHintNewVersion(boolean isHint){
- this.isHintNewVersion = isHint;
- return this;
- }
-
- /**
- * 构造UpdateManager对象
- *
- * @return
- */
- public UpdateHelper build() {
- return new UpdateHelper(this);
- }
- }
-
- private void installApk(Uri data) {
- if (mContext != null) {
- Intent i = new Intent(Intent.ACTION_VIEW);
- i.setDataAndType(data, "application/vnd.android.package-archive");
- i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- mContext.startActivity(i);
- if (notificationManager != null) {
- notificationManager.cancel(DOWNLOAD_NOTIFICATION_ID);
- }
- } else {
- Log.e("NullPointerException", "The context must not be null.");
- }
-
- }
-
-}
\ No newline at end of file
diff --git a/src/com/shelwee/update/utils/HttpRequest.java b/src/com/shelwee/update/utils/HttpRequest.java
deleted file mode 100644
index 9b5df6d..0000000
--- a/src/com/shelwee/update/utils/HttpRequest.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package com.shelwee.update.utils;
-
-import java.io.InputStream;
-import java.net.HttpURLConnection;
-import java.net.URL;
-
-import android.util.Log;
-
-/**
- *
- * @author ShelWee
- *
- */
-public class HttpRequest {
-
- public static InputStream get(String url){
- try {
- URL urlPath = new URL(url);
- HttpURLConnection httpURLConnection = (HttpURLConnection) urlPath.openConnection();
- httpURLConnection.setConnectTimeout(3000);
- httpURLConnection.setReadTimeout(3000);
- httpURLConnection.connect();
- InputStream inputStream = null;
- if(httpURLConnection.getResponseCode() == HttpURLConnection.HTTP_OK){
- inputStream = httpURLConnection.getInputStream();
- }
- return inputStream;
- } catch (Exception e) {
- e.printStackTrace();
- Log.e("TimeOut","the connection is timeout, maybe the server was closed.");
- return null;
- }
- }
-}
diff --git a/AndroidManifest.xml b/src/main/AndroidManifest.xml
similarity index 83%
rename from AndroidManifest.xml
rename to src/main/AndroidManifest.xml
index 51a80b9..d9c0696 100644
--- a/AndroidManifest.xml
+++ b/src/main/AndroidManifest.xml
@@ -1,5 +1,5 @@
@@ -9,7 +9,6 @@
diff --git a/src/main/java/com/shelwee/update/UpdateHelper.java b/src/main/java/com/shelwee/update/UpdateHelper.java
new file mode 100644
index 0000000..a74c0a1
--- /dev/null
+++ b/src/main/java/com/shelwee/update/UpdateHelper.java
@@ -0,0 +1,466 @@
+package com.shelwee.update;
+
+import android.Manifest;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Build;
+import android.os.Environment;
+import android.os.Handler;
+import android.os.Message;
+import android.support.v4.app.ActivityCompat;
+import android.support.v4.app.NotificationCompat;
+import android.util.Log;
+import android.widget.RemoteViews;
+import android.widget.Toast;
+
+import com.shelwee.update.listener.OnUpdateListener;
+import com.shelwee.update.pojo.UpdateInfo;
+import com.shelwee.update.utils.HttpRequest;
+import com.shelwee.update.utils.JSONHandler;
+import com.shelwee.update.utils.NetWorkUtils;
+import com.shelwee.update.utils.URLUtils;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+
+/**
+ * Created by Shelwee on 14-5-8.
+ * Usage:
+ *
+ * UpdateManager updateManager = new UpdateManager.Builder(this)
+ * .checkUrl("http://localhost/examples/version.jsp")
+ * .isAutoInstall(false)
+ * .build();
+ * updateManager.check();
+ *
+ *
+ * @author Shelwee(http://www.shelwee.com)
+ * @version 1.0
+ */
+public class UpdateHelper {
+
+ private Context mContext;
+ private String checkUrl;
+ private boolean isAutoInstall;
+ private boolean isHintVersion;
+ private OnUpdateListener updateListener;
+ private NotificationManager notificationManager;
+ private NotificationCompat.Builder ntfBuilder;
+ private static final int REQUEST_PERMISSION_CODE = 0x1;
+ private static final int COMPLETE_DOWNLOAD_APK = 0x2;
+ private static final int DOWNLOAD_NOTIFICATION_ID = 0x3;
+ private static final String PATH = Environment
+ .getExternalStorageDirectory().getPath();
+ private static final String SUFFIX = ".apk";
+ private static final String APK_PATH = "APK_PATH";
+ private static final String APP_NAME = "APP_NAME";
+ private SharedPreferences preferences_update;
+ private Notification mNotification;
+ private String permission = Manifest.permission.WRITE_EXTERNAL_STORAGE;
+
+ private HashMap cache = new HashMap();
+
+ private Handler handler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ super.handleMessage(msg);
+ switch (msg.what) {
+ case COMPLETE_DOWNLOAD_APK:
+ if (UpdateHelper.this.isAutoInstall) {
+ installApk(Uri.parse("file://" + cache.get(APK_PATH)));
+ } else {
+ ntfBuilder.setContentTitle(cache.get(APP_NAME))
+ .setContentText(mContext.getText(R.string.finished_install))
+ .setTicker(mContext.getText(R.string.download_done))
+ .setAutoCancel(true)
+ .setProgress(0, 0 ,true);
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setDataAndType(
+ Uri.parse("file://" + cache.get(APK_PATH)),
+ "application/vnd.android.package-archive");
+ PendingIntent pendingIntent = PendingIntent.getActivity(
+ mContext, 0, intent, 0);
+ ntfBuilder.setContentIntent(pendingIntent);
+ notificationManager.notify(DOWNLOAD_NOTIFICATION_ID,
+ ntfBuilder.build());
+ }
+ break;
+ }
+ }
+
+ };
+
+ private UpdateHelper(Builder builder) {
+ this.mContext = builder.context;
+ this.checkUrl = builder.checkUrl;
+ this.isAutoInstall = builder.isAutoInstall;
+ this.isHintVersion = builder.isHintNewVersion;
+ preferences_update = mContext.getSharedPreferences("Updater",
+ Context.MODE_PRIVATE);
+ notificationManager = (NotificationManager) mContext
+ .getSystemService(Context.NOTIFICATION_SERVICE);
+ }
+
+ /**
+ * 检查app是否有新版本,check之前先Builer所需参数
+ */
+ public void check() {
+ check(null);
+ }
+
+ public void check(OnUpdateListener listener) {
+ if (listener != null) {
+ this.updateListener = listener;
+ }
+ if (mContext == null) {
+ Log.e("NullPointerException", "The context must not be null.");
+ return;
+ }
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ if (ActivityCompat.checkSelfPermission(mContext, permission) != PackageManager.PERMISSION_GRANTED) {
+ ActivityCompat.requestPermissions((Activity) mContext, new String[]{permission}, REQUEST_PERMISSION_CODE);
+ }else {
+ startCheck();
+ }
+ }else {
+ startCheck();
+ }
+ }
+
+ private void startCheck() {
+ AsyncCheck asyncCheck = new AsyncCheck();
+ asyncCheck.execute(checkUrl);
+ }
+
+ /**
+ * 2014-10-27新增流量提示框,当网络为数据流量方式时,下载就会弹出此对话框提示
+ *
+ * @param updateInfo
+ */
+ private void showNetDialog(final UpdateInfo updateInfo) {
+ AlertDialog.Builder netBuilder = new AlertDialog.Builder(mContext);
+ netBuilder.setTitle(mContext.getText(R.string.download_tips));
+ netBuilder.setMessage(mContext.getText(R.string.download_tips_network));
+ netBuilder.setNegativeButton(mContext.getText(R.string.download_cancel),
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.dismiss();
+ }
+ });
+ netBuilder.setPositiveButton(mContext.getText(R.string.download_continue),
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.dismiss();
+ AsyncDownLoad asyncDownLoad = new AsyncDownLoad();
+ asyncDownLoad.execute(updateInfo);
+ }
+ });
+ AlertDialog netDialog = netBuilder.create();
+ netDialog.setCanceledOnTouchOutside(false);
+ netDialog.show();
+ }
+
+ /**
+ * 弹出提示更新窗口
+ *
+ * @param updateInfo
+ */
+ private void showUpdateUI(final UpdateInfo updateInfo) {
+ NetWorkUtils netWorkUtils = new NetWorkUtils(mContext);
+ final int type = netWorkUtils.getNetType();
+ if (updateInfo.isForceUpgrade()){
+ if (type != 1) {
+ showNetDialog(updateInfo);
+ } else {
+ AsyncDownLoad asyncDownLoad = new AsyncDownLoad();
+ asyncDownLoad.execute(updateInfo);
+ }
+ }else {
+ AlertDialog.Builder upDialogBuilder = new AlertDialog.Builder(mContext);
+ upDialogBuilder.setTitle(updateInfo.getUpdateTips());
+ upDialogBuilder.setMessage(updateInfo.getChangeLog());
+ upDialogBuilder.setNegativeButton(mContext.getText(R.string.next_time),
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.dismiss();
+ }
+ });
+ upDialogBuilder.setPositiveButton(mContext.getText(R.string.download),
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.dismiss();
+ if (type != 1) {
+ showNetDialog(updateInfo);
+ } else {
+ AsyncDownLoad asyncDownLoad = new AsyncDownLoad();
+ asyncDownLoad.execute(updateInfo);
+ }
+ }
+ });
+ AlertDialog updateDialog = upDialogBuilder.create();
+ updateDialog.setCanceledOnTouchOutside(false);
+ updateDialog.show();
+ }
+ }
+
+ /**
+ * 获取当前app版本
+ *
+ * @return
+ */
+ private PackageInfo getPackageInfo() {
+ PackageInfo pinfo = null;
+ if (mContext != null) {
+ try {
+ pinfo = mContext.getPackageManager().getPackageInfo(
+ mContext.getPackageName(), 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ e.printStackTrace();
+ }
+ }
+ return pinfo;
+ }
+
+ /**
+ * 检查更新任务
+ */
+ private class AsyncCheck extends AsyncTask {
+ @Override
+ protected void onPreExecute() {
+ super.onPreExecute();
+ if (UpdateHelper.this.updateListener != null) {
+ UpdateHelper.this.updateListener.onStartCheck();
+ }
+ }
+
+ @Override
+ protected UpdateInfo doInBackground(String... params) {
+ UpdateInfo updateInfo = null;
+ if (params.length == 0) {
+ Log.e("NullPointerException",
+ " Url parameter must not be null.");
+ return null;
+ }
+ String url = params[0];
+ if (!URLUtils.isNetworkUrl(url)) {
+ Log.e("IllegalArgument", "The URL is invalid.");
+ return null;
+ }
+ try {
+ updateInfo = JSONHandler.toUpdateInfo(new HttpRequest(url).get());
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ return updateInfo;
+ }
+
+ @Override
+ protected void onPostExecute(UpdateInfo updateInfo) {
+ super.onPostExecute(updateInfo);
+ SharedPreferences.Editor editor = preferences_update.edit();
+ if (mContext != null && updateInfo != null) {
+ if (Integer.parseInt(updateInfo.getVersionCode()) > getPackageInfo().versionCode) {
+ showUpdateUI(updateInfo);
+ editor.putBoolean("hasNewVersion", true);
+ editor.putString("latestVersionCode",
+ updateInfo.getVersionCode());
+ editor.putString("latestVersionName",
+ updateInfo.getVersionName());
+ } else {
+ if (isHintVersion) {
+ Toast.makeText(mContext, R.string.was_latest_version, Toast.LENGTH_LONG).show();
+ }
+ editor.putBoolean("hasNewVersion", false);
+ }
+ } else {
+ if (isHintVersion) {
+ Toast.makeText(mContext, R.string.was_latest_version, Toast.LENGTH_LONG).show();
+ }
+ }
+ editor.putString("currentVersionCode", getPackageInfo().versionCode + "");
+ editor.putString("currentVersionName", getPackageInfo().versionName);
+ editor.apply();
+ if (UpdateHelper.this.updateListener != null) {
+ UpdateHelper.this.updateListener.onFinishCheck(updateInfo);
+ }
+ }
+ }
+
+ /**
+ * 异步下载app任务
+ */
+ private class AsyncDownLoad extends AsyncTask {
+ @Override
+ protected void onPreExecute() {
+ notificationManager.cancel(DOWNLOAD_NOTIFICATION_ID);
+ PendingIntent contentIntent = PendingIntent.getActivity(mContext,
+ 0, new Intent(), PendingIntent.FLAG_UPDATE_CURRENT);
+ ntfBuilder = new NotificationCompat.Builder(mContext)
+ .setOngoing(true)
+ .setSmallIcon(mContext.getApplicationInfo().icon)
+ .setTicker(mContext.getResources().getText(R.string.start_download) + "...")
+ .setContentIntent(contentIntent)
+ .setProgress(100, 0, false);
+ mNotification = ntfBuilder.build();
+ notificationManager.notify(DOWNLOAD_NOTIFICATION_ID, mNotification);
+ }
+
+ @Override
+ protected Boolean doInBackground(UpdateInfo... params) {
+ String apkUrl = params[0].getApkUrl();
+ HttpRequest request = new HttpRequest(apkUrl);
+ try {
+ long apkTotalLength = request.getContentLength();
+ String apkName = params[0].getAppName()
+ + params[0].getVersionName() + SUFFIX;
+ cache.put(APP_NAME, params[0].getAppName());
+ cache.put(APK_PATH,
+ PATH + File.separator + params[0].getAppName()
+ + File.separator + apkName);
+ File savePath = new File(PATH + File.separator
+ + params[0].getAppName());
+ if (!savePath.exists())
+ savePath.mkdirs();
+ File apkFile = new File(savePath, apkName);
+ if (apkFile.exists() && apkFile.length() == apkTotalLength) {
+ return true;
+ }
+ FileOutputStream fos = new FileOutputStream(apkFile);
+ InputStream inputStream = request.get();
+ if (inputStream == null) {
+ return false;
+ }
+ byte[] buf = new byte[2048];
+ int count = 0;
+ int length = 0;
+ int progress = 0;
+ while ((length = inputStream.read(buf)) > 0) {
+ fos.write(buf, 0, length);
+ count += length;
+ if ((progress == 0)
+ || (int) (count * 100 / apkTotalLength) > progress) {
+ progress += 1;
+ publishProgress(progress);
+ }
+ if (UpdateHelper.this.updateListener != null) {
+ UpdateHelper.this.updateListener
+ .onDownloading(progress);
+ }
+ }
+ inputStream.close();
+ fos.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ protected void onProgressUpdate(Integer... values) {
+ ntfBuilder.setContentTitle(cache.get(APP_NAME))
+ .setContentText(mContext.getResources().getText(R.string.download_progress) + ": " + values[0] + "%")
+ .setProgress(100, values[0], false);
+ mNotification = ntfBuilder.build();
+ notificationManager.notify(DOWNLOAD_NOTIFICATION_ID, mNotification);
+ }
+
+ @Override
+ protected void onPostExecute(Boolean flag) {
+ if (flag) {
+ handler.obtainMessage(COMPLETE_DOWNLOAD_APK).sendToTarget();
+ if (UpdateHelper.this.updateListener != null) {
+ UpdateHelper.this.updateListener.onFinshDownload();
+ }
+ } else {
+ Log.e("Error", "check your network connction");
+ }
+ }
+ }
+
+ public static class Builder {
+ private Context context;
+ private String checkUrl;
+ private boolean isAutoInstall = true;
+ private boolean isHintNewVersion = true;
+
+ public Builder(Context ctx) {
+ this.context = ctx;
+ }
+
+ /**
+ * 检查是否有新版本App的URL接口路径
+ *
+ * @param checkUrl
+ * @return
+ */
+ public Builder checkUrl(String checkUrl) {
+ this.checkUrl = checkUrl;
+ return this;
+ }
+
+ /**
+ * 是否需要自动安装, 不设置默认自动安装
+ *
+ * @param isAuto true下载完成后自动安装,false下载完成后需在通知栏手动点击安装
+ * @return
+ */
+ public Builder isAutoInstall(boolean isAuto) {
+ this.isAutoInstall = isAuto;
+ return this;
+ }
+
+ /**
+ * 当没有新版本时,是否Toast提示
+ *
+ * @param isHint
+ * @return true提示,false不提示
+ */
+ public Builder isHintNewVersion(boolean isHint) {
+ this.isHintNewVersion = isHint;
+ return this;
+ }
+
+ /**
+ * 构造UpdateManager对象
+ *
+ * @return
+ */
+ public UpdateHelper build() {
+ return new UpdateHelper(this);
+ }
+ }
+
+ private void installApk(Uri data) {
+ if (mContext != null) {
+ Intent i = new Intent(Intent.ACTION_VIEW);
+ i.setDataAndType(data, "application/vnd.android.package-archive");
+ i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivity(i);
+ if (notificationManager != null) {
+ notificationManager.cancel(DOWNLOAD_NOTIFICATION_ID);
+ }
+ } else {
+ Log.e("NullPointerException", "The context must not be null.");
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/com/shelwee/update/listener/OnUpdateListener.java b/src/main/java/com/shelwee/update/listener/OnUpdateListener.java
similarity index 92%
rename from src/com/shelwee/update/listener/OnUpdateListener.java
rename to src/main/java/com/shelwee/update/listener/OnUpdateListener.java
index 2820c77..ba645d9 100644
--- a/src/com/shelwee/update/listener/OnUpdateListener.java
+++ b/src/main/java/com/shelwee/update/listener/OnUpdateListener.java
@@ -3,7 +3,7 @@
import com.shelwee.update.pojo.UpdateInfo;
/**
- * Created by ShelWee on 14-5-16.
+ * Created by Shelwee on 14-5-16.
*/
public interface OnUpdateListener {
/**
diff --git a/src/com/shelwee/update/pojo/UpdateInfo.java b/src/main/java/com/shelwee/update/pojo/UpdateInfo.java
similarity index 85%
rename from src/com/shelwee/update/pojo/UpdateInfo.java
rename to src/main/java/com/shelwee/update/pojo/UpdateInfo.java
index b53d834..ec0cbe3 100644
--- a/src/com/shelwee/update/pojo/UpdateInfo.java
+++ b/src/main/java/com/shelwee/update/pojo/UpdateInfo.java
@@ -2,7 +2,7 @@
/**
- * Created by ShelWee on 14-5-8.
+ * Created by Shelwee on 14-5-8.
*/
public class UpdateInfo {
private String appName;
@@ -12,6 +12,7 @@ public class UpdateInfo {
private String apkUrl;
private String changeLog;
private String updateTips;
+ private boolean forceUpgrade;
public String getAppName() {
return appName;
@@ -68,4 +69,12 @@ public String getChangeLog() {
public void setChangeLog(String changeLog) {
this.changeLog = changeLog;
}
+
+ public boolean isForceUpgrade() {
+ return forceUpgrade;
+ }
+
+ public void setForceUpgrade(boolean forceUpgrade) {
+ this.forceUpgrade = forceUpgrade;
+ }
}
diff --git a/src/main/java/com/shelwee/update/utils/HttpRequest.java b/src/main/java/com/shelwee/update/utils/HttpRequest.java
new file mode 100644
index 0000000..e62493a
--- /dev/null
+++ b/src/main/java/com/shelwee/update/utils/HttpRequest.java
@@ -0,0 +1,62 @@
+package com.shelwee.update.utils;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+
+import android.util.Log;
+
+/**
+ * Created by Shelwee on 14-5-8.
+ */
+public class HttpRequest {
+
+ private String url;
+
+ public HttpRequest(String url) {
+ this.url = url;
+ }
+
+ private HttpURLConnection buildConnection() throws IOException {
+ URL urlPath = new URL(url);
+ HttpURLConnection httpURLConnection = (HttpURLConnection) urlPath.openConnection();
+ httpURLConnection.setConnectTimeout(8000);
+ httpURLConnection.setReadTimeout(5000);
+ return httpURLConnection;
+ }
+
+ public int getContentLength(){
+ HttpURLConnection httpURLConnection = null;
+ try {
+ httpURLConnection = buildConnection();
+ httpURLConnection.connect();
+ int length = 0;
+ if(httpURLConnection.getResponseCode() == HttpURLConnection.HTTP_OK){
+ length = httpURLConnection.getContentLength();
+ }
+ return length;
+ } catch (Exception e) {
+ e.printStackTrace();
+ Log.e("Request Exception","the connection is timeout or maybe the server was closed.");
+ return 0;
+ }
+ }
+
+ public InputStream get(){
+ HttpURLConnection httpURLConnection = null;
+ InputStream inputStream = null;
+ try {
+ httpURLConnection = buildConnection();
+ httpURLConnection.connect();
+ if(httpURLConnection.getResponseCode() == HttpURLConnection.HTTP_OK){
+ inputStream = httpURLConnection.getInputStream();
+ }
+ return inputStream;
+ } catch (Exception e) {
+ e.printStackTrace();
+ Log.e("Request Exception","the connection is timeout or maybe the server was closed.");
+ return null;
+ }
+ }
+}
diff --git a/src/com/shelwee/update/utils/JSONHandler.java b/src/main/java/com/shelwee/update/utils/JSONHandler.java
similarity index 77%
rename from src/com/shelwee/update/utils/JSONHandler.java
rename to src/main/java/com/shelwee/update/utils/JSONHandler.java
index 715616b..dab7d38 100644
--- a/src/com/shelwee/update/utils/JSONHandler.java
+++ b/src/main/java/com/shelwee/update/utils/JSONHandler.java
@@ -9,12 +9,12 @@
import com.shelwee.update.pojo.UpdateInfo;
/**
- * Created by ShelWee on 14-5-8.
+ * Created by Shelwee on 14-5-8.
*/
public class JSONHandler {
public static UpdateInfo toUpdateInfo(InputStream is) throws Exception {
- if (is == null){
+ if (is == null) {
return null;
}
String byteData = new String(readStream(is));
@@ -27,15 +27,16 @@ public static UpdateInfo toUpdateInfo(InputStream is) throws Exception {
updateInfo.setVersionName(jsonObject.getString("versionName"));
updateInfo.setChangeLog(jsonObject.getString("changeLog"));
updateInfo.setUpdateTips(jsonObject.getString("updateTips"));
+ updateInfo.setForceUpgrade(jsonObject.getBoolean("forceUpgrade"));
return updateInfo;
}
private static byte[] readStream(InputStream inputStream) throws IOException {
- ByteArrayOutputStream outputStream=new ByteArrayOutputStream();
- byte [] array=new byte[1024];
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ byte[] array = new byte[1024];
int len = 0;
- while( (len = inputStream.read(array)) != -1){
- outputStream.write(array,0,len);
+ while ((len = inputStream.read(array)) != -1) {
+ outputStream.write(array, 0, len);
}
inputStream.close();
outputStream.close();
diff --git a/src/com/shelwee/update/utils/NetWorkUtils.java b/src/main/java/com/shelwee/update/utils/NetWorkUtils.java
similarity index 96%
rename from src/com/shelwee/update/utils/NetWorkUtils.java
rename to src/main/java/com/shelwee/update/utils/NetWorkUtils.java
index b456d68..ea7da20 100644
--- a/src/com/shelwee/update/utils/NetWorkUtils.java
+++ b/src/main/java/com/shelwee/update/utils/NetWorkUtils.java
@@ -5,7 +5,7 @@
import android.net.NetworkInfo;
/**
- * Created by ShelWee on 14-5-8.
+ * Created by Shelwee on 14-5-8.
*/
public class NetWorkUtils {
diff --git a/src/com/shelwee/update/utils/URLUtils.java b/src/main/java/com/shelwee/update/utils/URLUtils.java
similarity index 94%
rename from src/com/shelwee/update/utils/URLUtils.java
rename to src/main/java/com/shelwee/update/utils/URLUtils.java
index ac296a8..6107d91 100644
--- a/src/com/shelwee/update/utils/URLUtils.java
+++ b/src/main/java/com/shelwee/update/utils/URLUtils.java
@@ -1,7 +1,7 @@
package com.shelwee.update.utils;
/**
- * Created by ShelWee on 14-5-8.
+ * Created by Shelwee on 14-5-8.
*/
public class URLUtils {
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
new file mode 100644
index 0000000..729068b
--- /dev/null
+++ b/src/main/res/values/strings.xml
@@ -0,0 +1,17 @@
+
+
+ android-updater
+ 开始下载
+ 下载进度
+ 当前已是最新版
+ 下载完成,点击安装
+ 任务下载完成
+ 下载提示
+ 您在目前的网络环境下继续下载将可能会消耗手机流量,请确认是否继续下载?
+ 取消下载
+ 继续下载
+ 下次再说
+ 下载
+ 请允许应用添加存储权限
+
+
diff --git a/res/values/styles.xml b/src/main/res/values/styles.xml
similarity index 100%
rename from res/values/styles.xml
rename to src/main/res/values/styles.xml