diff --git a/.gitignore b/.gitignore index eef2d45..63fc54f 100644 --- a/.gitignore +++ b/.gitignore @@ -39,5 +39,6 @@ captures/ .idea/vcs.xml .idea/libraries + # Keystore files *.jks diff --git a/README.md b/README.md index fde3234..438a057 100644 --- a/README.md +++ b/README.md @@ -1,29 +1,59 @@ -### 你知道吗?Github的 “star” 功能就像微信朋友圈中的 **“点赞”** 功能,如果你觉得我的代码对你有帮助,你可以帮我点个赞,随手 “star” 一下。 - - +# 应用截图 + + + + + + + +
# AndroidModulePattern + Android项目组件化示例代码 -博客:http://blog.csdn.net/guiying712/article/details/55213884 +**Android组件化方案**:http://blog.csdn.net/guiying712/article/details/55213884 + +**Android组件化之终极方案**:http://blog.csdn.net/guiying712/article/details/78057120 + +1. 现在的 AndroidModulePattern 使用 阿里ARouter作为路由; + +2. Android组件化方案已经支持 **Fragment组件化**,使用方法请下载Demo查看; + +3. 本项目已适配Android Studio 3.0.1版本(Google仓库会带来一定影响) + + +## 集成开发模式和组件开发模式转换 + +**1、首先打开Android项目的 gradle.properties 文件,然后将 isModule 改为你需要的开发模式(true/false), +然后点击 "Sync Project" 按钮同步项目;** + +**2、![Image](/screenshots/develper.PNG) 在运行之前,请先按照图中选择一个能够运行的组件;** + + +## 组件功能介绍 -### app组件功能: -1. app组件主要用于管理其他组件; +### app组件功能(空壳工程): +1. 配置整个项目的Gradle脚本,例如 混淆、签名等; 2. app组件中可以初始化全局的库,例如Lib.init(this); 3. 添加 multiDex 功能 +4. 业务组件管理(组装); -### main组件功能: +### main组件功能(业务组件): 1. 声明应用的launcherActivity----->android.intent.category.LAUNCHER; 2. 添加SplashActivity; 3. 添加LoginActivity; +4. 添加MainActivity; -### girls/news组件功能: -1. 这两个组件都是业务组件,根据产品功能独立成一个模块; +### girls/news组件功能(业务组件): +1. 这两个组件都是业务组件,根据产品的业务逻辑独立成一个组件; -### common组件功能: +### common组件功能(功能组件): 1. common组件是基础库,添加一些公用的类; 2. 例如:网络请求、图片加载、工具类、base类等等; +3. 声明APP需要的uses-permission; +4. 定义全局通用的主题(Theme); ## License @@ -39,4 +69,4 @@ Android项目组件化示例代码 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. \ No newline at end of file + limitations under the License. diff --git a/app/build.gradle b/app/build.gradle deleted file mode 100644 index eb8760c..0000000 --- a/app/build.gradle +++ /dev/null @@ -1,64 +0,0 @@ -apply plugin: 'com.android.application' -apply plugin: 'com.neenbedankt.android-apt' - -def buildTime() { - return new Date().format("yyyyMMdd"); -} - -android { - compileSdkVersion rootProject.ext.compileSdkVersion - buildToolsVersion rootProject.ext.buildToolsVersion - defaultConfig { - applicationId "com.guiying.androidmodulepattern" - minSdkVersion rootProject.ext.minSdkVersion - targetSdkVersion rootProject.ext.targetSdkVersion - versionCode rootProject.ext.versionCode - versionName rootProject.ext.versionName - //multiDexEnabled true - //打包时间 - resValue "string", "build_time", buildTime() - } - - buildTypes { - release { - //更改AndroidManifest.xml中预先定义好占位符信息 - //manifestPlaceholders = [app_icon: "@drawable/icon"] - // 不显示Log - buildConfigField "boolean", "LEO_DEBUG", "false" - //是否zip对齐 - zipAlignEnabled true - // 缩减resource文件 - shrinkResources true - //Proguard - minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - //签名 - //signingConfig signingConfigs.release - } - - debug { - //给applicationId添加后缀“.debug” - applicationIdSuffix ".debug" - //manifestPlaceholders = [app_icon: "@drawable/launch_beta"] - buildConfigField "boolean", "LOG_DEBUG", "true" - zipAlignEnabled false - shrinkResources false - minifyEnabled false - debuggable true - } - } -} - -dependencies { - compile fileTree(dir: 'libs', include: ['*.jar']) - - if (!isModule.toBoolean()) { - compile project(':main') - compile project(':girls') - compile project(':news') - } else { - compile project(':common') - } - //router - apt "com.github.mzule.activityrouter:compiler:$rootProject.aptCompilerVersion" -} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro deleted file mode 100644 index 1fa287c..0000000 --- a/app/proguard-rules.pro +++ /dev/null @@ -1,17 +0,0 @@ -# Add project specific ProGuard rules here. -# By default, the flags in this file are appended to flags specified -# in D:\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 *; -#} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml deleted file mode 100644 index 0daa87f..0000000 --- a/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/java/com/guiying/androidmodulepattern/App.java b/app/src/main/java/com/guiying/androidmodulepattern/App.java deleted file mode 100644 index c1858cf..0000000 --- a/app/src/main/java/com/guiying/androidmodulepattern/App.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.guiying.androidmodulepattern; - -import com.github.mzule.activityrouter.annotation.Module; - -/** - *

这就是个壳工程,没有任何界面,只负责管理组件

- * - * @author 张华洋 2017/2/15 20:42 - * @version V1.2.0 - * @name AppModule - */ - -@Module("app") -public class App { -} diff --git a/app/src/main/java/com/guiying/androidmodulepattern/MyApplication.java b/app/src/main/java/com/guiying/androidmodulepattern/MyApplication.java deleted file mode 100644 index 9fb5a5b..0000000 --- a/app/src/main/java/com/guiying/androidmodulepattern/MyApplication.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.guiying.androidmodulepattern; - -import com.github.mzule.activityrouter.annotation.Modules; -import com.guiying.common.base.BaseApplication; - -/** - *

应用程序的Application只负责管理组件

- * - * @author 张华洋 2017/2/15 20:14 - * @version V1.2.0 - * @name MyApplication - */ -@Modules({"app", "main", "girls", "news"}) -public class MyApplication extends BaseApplication { - - - @Override - public void onCreate() { - super.onCreate(); - } - -} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml deleted file mode 100644 index 99d6e54..0000000 --- a/app/src/main/res/values/strings.xml +++ /dev/null @@ -1,6 +0,0 @@ - - 组件化项目 - - module - - diff --git a/build.gradle b/build.gradle index 0e0ef19..40fe932 100644 --- a/build.gradle +++ b/build.gradle @@ -1,58 +1,38 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - repositories { - jcenter() - mavenCentral() - } - + apply from: 'versions.gradle' + addRepos(repositories) dependencies { - classpath "com.android.tools.build:gradle:$localGradlePluginVersion" - classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' + /* classpath deps.android_gradle_plugin*/ + classpath deps.android_gradle_plugin + classpath deps.kotlin.plugin // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } } allprojects { - repositories { - jcenter() - mavenCentral() - //Add the JitPack repository - maven { url "https://jitpack.io" } - //支持arr包 - flatDir { - dirs 'libs' + addRepos(repositories) + // Android dependency 'com.android.support:design' has different version for the compile (25.3.1) and runtime (25.4.0) classpath. + // You should manually set the same version via DependencyResolution + subprojects { + project.configurations.all { + resolutionStrategy.eachDependency { details -> + if (details.requested.group == 'com.android.support' + && !details.requested.name.contains('multidex')) { + details.useVersion "27.0.2" + } + } } } + + // 组件缓存更新时间设置(默认每次build都更新) + configurations.all { + resolutionStrategy.cacheChangingModulesFor 0, 'minutes' + } } task clean(type: Delete) { delete rootProject.buildDir -} - -// Define versions in a single place -ext { - // Sdk and tools - buildToolsVersion = localBuildToolsVersion - compileSdkVersion = 25 - minSdkVersion = 15 - targetSdkVersion = 25 - versionCode = 1 - versionName = "1.0" - javaVersion = JavaVersion.VERSION_1_8 - - // App dependencies version - supportLibraryVersion = "25.3.0" - retrofitVersion = "2.1.0" - glideVersion = "3.7.0" - loggerVersion = "1.15" - eventbusVersion = "3.0.0" - gsonVersion = "2.8.0" - - //不成熟开源库,需经常检查升级版本 - aptCompilerVersion = "1.1.7" - routerVersion = "1.2.2" - easyRecyclerVersion = "4.4.0" - cookieVersion = "v1.0.1" -} +} \ No newline at end of file diff --git a/common/build.gradle b/common/build.gradle deleted file mode 100644 index 6393bd6..0000000 --- a/common/build.gradle +++ /dev/null @@ -1,42 +0,0 @@ -apply plugin: 'com.android.library' - -android { - compileSdkVersion rootProject.ext.compileSdkVersion - buildToolsVersion rootProject.ext.buildToolsVersion - - defaultConfig { - minSdkVersion rootProject.ext.minSdkVersion - targetSdkVersion rootProject.ext.targetSdkVersion - versionCode rootProject.ext.versionCode - versionName rootProject.ext.versionName - } - - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - } - } -} - -dependencies { - compile fileTree(dir: 'libs', include: ['*.jar']) - //Android Support - compile "com.android.support:appcompat-v7:$rootProject.supportLibraryVersion" - compile "com.android.support:design:$rootProject.supportLibraryVersion" - compile "com.android.support:percent:$rootProject.supportLibraryVersion" - //网络请求相关 - compile "com.squareup.retrofit2:retrofit:$rootProject.retrofitVersion" - compile "com.squareup.retrofit2:retrofit-mock:$rootProject.retrofitVersion" - compile "com.github.franmontiel:PersistentCookieJar:$rootProject.cookieVersion" - //稳定的 - compile "com.github.bumptech.glide:glide:$rootProject.glideVersion" - compile "com.orhanobut:logger:$rootProject.loggerVersion" - compile "org.greenrobot:eventbus:$rootProject.eventbusVersion" - compile "com.google.code.gson:gson:$rootProject.gsonVersion" - //不稳定的 - compile "com.github.mzule.activityrouter:activityrouter:$rootProject.routerVersion" - compile "com.jude:easyrecyclerview:$rootProject.easyRecyclerVersion" - - compile 'com.github.GrenderG:Toasty:1.1.3' -} diff --git a/common/proguard-rules.pro b/common/proguard-rules.pro deleted file mode 100644 index 1fa287c..0000000 --- a/common/proguard-rules.pro +++ /dev/null @@ -1,17 +0,0 @@ -# Add project specific ProGuard rules here. -# By default, the flags in this file are appended to flags specified -# in D:\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 *; -#} diff --git a/common/src/main/AndroidManifest.xml b/common/src/main/AndroidManifest.xml deleted file mode 100644 index e144c94..0000000 --- a/common/src/main/AndroidManifest.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/common/src/main/java/com/guiying/common/base/BaseActionBarActivity.java b/common/src/main/java/com/guiying/common/base/BaseActionBarActivity.java deleted file mode 100644 index 721b558..0000000 --- a/common/src/main/java/com/guiying/common/base/BaseActionBarActivity.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * @ProjectName: ISMS_Petrel_MCU - * @Copyright: 2017 HangZhou Hikvision System Technology Co., Ltd. All Right Reserved. - * @address: http://www.hikvision.com - * @Description: 本内容仅限于杭州海康威视系统技术公有限司内部使用,禁止转发. - */ - -package com.guiying.common.base; - -import android.os.Bundle; -import android.support.annotation.StringRes; -import android.support.v7.app.ActionBar; - -/** - * BaseActionBarActivity继承于BaseActivity,封装了actionBar的逻辑; - * 继承于ActionBarBaseActivity的Activity都将默认带有ActionBar,并且只能使用AppTheme主题; - * 只有那些ActionBar只带有Title和返回按钮的Activity方可继承 - * - * @author 张华洋 2017/3/7 18:36 - * @version V1.2.0 - * @name BaseActionBarActivity - */ -public abstract class BaseActionBarActivity extends BaseActivity { - - protected abstract - @StringRes - int setTitleId(); - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - //标题栏设置 - ActionBar actionBar = getSupportActionBar(); - if (actionBar != null) { - actionBar.setDisplayHomeAsUpEnabled(true); - actionBar.setHomeButtonEnabled(true); - actionBar.setTitle(setTitleId()); - } - } - - - /** - * 更新标题 - * - * @param title 标题 - */ - protected void setTitle(String title) { - ActionBar actionBar = getSupportActionBar(); - if (actionBar != null) { - actionBar.setTitle(title); - } - } - - - @Override - public boolean onSupportNavigateUp() { - onBackPressed(); - return true; - } -} diff --git a/common/src/main/java/com/guiying/common/base/BaseActivity.java b/common/src/main/java/com/guiying/common/base/BaseActivity.java deleted file mode 100644 index fc73bf1..0000000 --- a/common/src/main/java/com/guiying/common/base/BaseActivity.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.guiying.common.base; - -import android.content.Intent; -import android.os.Bundle; -import android.support.annotation.IdRes; -import android.support.v7.app.ActionBar; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.Toolbar; -import android.view.View; - -/** - *

Activity基类

- * - * @author 2016/12/2 17:33 - * @version V1.0.0 - * @name BaseActivity - */ -public abstract class BaseActivity extends AppCompatActivity { - - /** - * 处理Intent,防止开发人员没做Intent判空 - */ - protected void handleIntent(Intent intent) { - } - - /** - * 封装的findViewByID方法 - */ - @SuppressWarnings("unchecked") - protected T $(@IdRes int id) { - return (T) super.findViewById(id); - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - BaseApplication.getIns().addActivity(this); - //强制在基类Intent判空 - if (null != getIntent()) { - handleIntent(getIntent()); - } - } - - protected void setToolbar(Toolbar toolbar, String title) { - setSupportActionBar(toolbar); - ActionBar actionBar = getSupportActionBar(); - if (null != actionBar) { - actionBar.setDisplayHomeAsUpEnabled(true); - actionBar.setDisplayShowHomeEnabled(true); - //actionBar.setDisplayShowTitleEnabled(false);//隐藏Title - actionBar.setTitle(title); - } - } - - @Override - protected void onDestroy() { - super.onDestroy(); - BaseApplication.getIns().finishActivity(this); - } - -} diff --git a/common/src/main/java/com/guiying/common/base/BasePresenter.java b/common/src/main/java/com/guiying/common/base/BasePresenter.java deleted file mode 100644 index c05c925..0000000 --- a/common/src/main/java/com/guiying/common/base/BasePresenter.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.guiying.common.base; - -public interface BasePresenter { - - void start(); - -} diff --git a/common/src/main/java/com/guiying/common/base/BaseView.java b/common/src/main/java/com/guiying/common/base/BaseView.java deleted file mode 100644 index debd151..0000000 --- a/common/src/main/java/com/guiying/common/base/BaseView.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.guiying.common.base; - -public interface BaseView { - - void setPresenter(T presenter); - -} diff --git a/common/src/main/java/com/guiying/common/http/HttpsUtil.java b/common/src/main/java/com/guiying/common/http/HttpsUtil.java deleted file mode 100644 index 6085aae..0000000 --- a/common/src/main/java/com/guiying/common/http/HttpsUtil.java +++ /dev/null @@ -1,296 +0,0 @@ -package com.guiying.common.http; - -import android.annotation.SuppressLint; -import android.content.Context; -import android.os.Build; -import android.support.annotation.RawRes; - -import java.io.IOException; -import java.io.InputStream; -import java.net.InetAddress; -import java.net.Socket; -import java.net.UnknownHostException; -import java.security.KeyManagementException; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.UnrecoverableKeyException; -import java.security.cert.Certificate; -import java.security.cert.CertificateException; -import java.security.cert.CertificateFactory; -import java.security.cert.X509Certificate; - -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.KeyManager; -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSession; -import javax.net.ssl.SSLSocket; -import javax.net.ssl.SSLSocketFactory; -import javax.net.ssl.TrustManager; -import javax.net.ssl.TrustManagerFactory; -import javax.net.ssl.X509TrustManager; - -/** - * HttpsUtils来自于鸿洋的: https://github.com/hongyangAndroid/okhttputils; - * 增加了主机名校验方法getHostnameVerifier(); - * 其他参考的文章有:http://android.jobbole.com/83787/; - * - * Android 4.X 对TLS1.1、TLS1.2的支持参考了http://blog.csdn.net/joye123/article/details/53888252 - */ -public class HttpsUtil { - - /** - * 包装的 SSL(Secure Socket Layer)参数类 - */ - public static class SSLParams { - public SSLSocketFactory sSLSocketFactory; - public X509TrustManager trustManager; - } - - /** - * @param context 上下文 - * @param certificatesId "XXX.cer" 文件 (文件位置res/raw/XXX.cer) - * @param bksFileId "XXX.bks"文件(文件位置res/raw/XXX.bks) - * @param password The certificate's password. - * @return SSLParams - */ - public static SSLParams getSslSocketFactory(Context context, @RawRes int[] certificatesId, @RawRes int bksFileId, String password) { - if (context == null) { - throw new NullPointerException("context == null"); - } - SSLParams sslParams = new SSLParams(); - try { - TrustManager[] trustManagers = prepareTrustManager(context, certificatesId); - KeyManager[] keyManagers = prepareKeyManager(context, bksFileId, password); - - //创建TLS类型的SSLContext对象,that uses our TrustManager - SSLContext sslContext = SSLContext.getInstance("TLS"); - - X509TrustManager x509TrustManager; - if (trustManagers != null) { - x509TrustManager = new MyTrustManager(chooseTrustManager(trustManagers)); - } else { - x509TrustManager = new UnSafeTrustManager(); - } - //用上面得到的trustManagers初始化SSLContext,这样sslContext就会信任keyStore中的证书 - sslContext.init(keyManagers, new TrustManager[]{x509TrustManager}, null); - - //通过sslContext获取SSLSocketFactory对象 - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { - /*Android 4.X 对TLS1.1、TLS1.2的支持*/ - sslParams.sSLSocketFactory = new Tls12SocketFactory(sslContext.getSocketFactory()); - sslParams.trustManager = x509TrustManager; - return sslParams; - } - - sslParams.sSLSocketFactory = sslContext.getSocketFactory(); - sslParams.trustManager = x509TrustManager; - return sslParams; - } catch (NoSuchAlgorithmException | KeyManagementException | KeyStoreException e) { - throw new AssertionError(e); - } - } - - - /** - * 主机名校验方法 - */ - public static HostnameVerifier getHostnameVerifier() { - return new HostnameVerifier() { - @Override - public boolean verify(String hostname, SSLSession session) { - return hostname.equalsIgnoreCase(session.getPeerHost()); - } - }; - } - - - private static TrustManager[] prepareTrustManager(Context context, int[] certificatesId) { - if (certificatesId == null || certificatesId.length <= 0) { - return null; - } - - try { - //创建X.509格式的CertificateFactory - CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); - // 创建一个默认类型的KeyStore,存储我们信任的证书 - KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); - keyStore.load(null); - int index = 0; - for (int certificateId : certificatesId) { - //从本地资源中获取证书的流 - InputStream cerInputStream = context.getResources().openRawResource(certificateId); - String certificateAlias = Integer.toString(index++); - - //certificate是java.security.cert.Certificate,而不是其他Certificate - //证书工厂根据证书文件的流生成证书Certificate - Certificate certificate = certificateFactory.generateCertificate(cerInputStream); - //将证书certificate作为信任的证书放入到keyStore中 - keyStore.setCertificateEntry(certificateAlias, certificate); - try { - if (cerInputStream != null) - cerInputStream.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - - //TrustManagerFactory是用于生成TrustManager的,这里创建一个默认类型的TrustManagerFactory - TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); - //用我们之前的keyStore实例初始化TrustManagerFactory,这样trustManagerFactory就会信任keyStore中的证书 - trustManagerFactory.init(keyStore); - return trustManagerFactory.getTrustManagers(); - } catch (Exception e) { - e.printStackTrace(); - } - return null; - } - - - private static KeyManager[] prepareKeyManager(Context context, @RawRes int bksFileId, String password) { - - try { - KeyStore clientKeyStore = KeyStore.getInstance("BKS"); - clientKeyStore.load(context.getResources().openRawResource(bksFileId), password.toCharArray()); - KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); - keyManagerFactory.init(clientKeyStore, password.toCharArray()); - return keyManagerFactory.getKeyManagers(); - - } catch (KeyStoreException | NoSuchAlgorithmException | UnrecoverableKeyException | CertificateException | IOException e) { - e.printStackTrace(); - } - return null; - } - - - private static X509TrustManager chooseTrustManager(TrustManager[] trustManagers) { - for (TrustManager trustManager : trustManagers) { - if (trustManager instanceof X509TrustManager) { - return (X509TrustManager) trustManager; - } - } - return null; - } - - - /** - * 客户端不对证书做任何检查; - * 客户端不对证书做任何验证的做法有很大的安全漏洞。 - */ - private static class UnSafeTrustManager implements X509TrustManager { - - @SuppressLint("TrustAllX509TrustManager") - @Override - public void checkClientTrusted(X509Certificate[] chain, String authType) - throws CertificateException { - } - - @SuppressLint("TrustAllX509TrustManager") - @Override - public void checkServerTrusted(X509Certificate[] chain, String authType) - throws CertificateException { - } - - @Override - public X509Certificate[] getAcceptedIssuers() { - return new X509Certificate[]{}; - } - } - - - private static class MyTrustManager implements X509TrustManager { - private X509TrustManager defaultTrustManager; - private X509TrustManager localTrustManager; - - private MyTrustManager(X509TrustManager localTrustManager) throws NoSuchAlgorithmException, KeyStoreException { - //TrustManagerFactory是用于生成TrustManager的,创建一个默认类型的TrustManagerFactory - TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); - trustManagerFactory.init((KeyStore) null); - defaultTrustManager = chooseTrustManager(trustManagerFactory.getTrustManagers()); - this.localTrustManager = localTrustManager; - } - - - @SuppressLint("TrustAllX509TrustManager") - @Override - public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { - - } - - @Override - public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { - try { - defaultTrustManager.checkServerTrusted(chain, authType); - } catch (CertificateException ce) { - localTrustManager.checkServerTrusted(chain, authType); - } - } - - - @Override - public X509Certificate[] getAcceptedIssuers() { - return new X509Certificate[0]; - } - } - - - /** - * 自行实现SSLSocketFactory ,实现Android 4.X 对TLSv1.1、TLSv1.2的支持 - */ - private static class Tls12SocketFactory extends SSLSocketFactory { - - private static final String[] TLS_SUPPORT_VERSION = {"TLSv1.1", "TLSv1.2"}; - - final SSLSocketFactory delegate; - - private Tls12SocketFactory(SSLSocketFactory base) { - this.delegate = base; - } - - @Override - public String[] getDefaultCipherSuites() { - return delegate.getDefaultCipherSuites(); - } - - @Override - public String[] getSupportedCipherSuites() { - return delegate.getSupportedCipherSuites(); - } - - @Override - public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException { - return patch(delegate.createSocket(s, host, port, autoClose)); - } - - @Override - public Socket createSocket(String host, int port) throws IOException, UnknownHostException { - return patch(delegate.createSocket(host, port)); - } - - @Override - public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException { - return patch(delegate.createSocket(host, port, localHost, localPort)); - } - - @Override - public Socket createSocket(InetAddress host, int port) throws IOException { - return patch(delegate.createSocket(host, port)); - } - - @Override - public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException { - return patch(delegate.createSocket(address, port, localAddress, localPort)); - } - - private Socket patch(Socket s) { - //代理SSLSocketFactory在创建一个Socket连接的时候,会设置Socket的可用的TLS版本。 - if (s instanceof SSLSocket) { - ((SSLSocket) s).setEnabledProtocols(TLS_SUPPORT_VERSION); - } - return s; - } - } - - -} diff --git a/girls/build.gradle b/girls/build.gradle deleted file mode 100644 index 7fd1812..0000000 --- a/girls/build.gradle +++ /dev/null @@ -1,50 +0,0 @@ -if (isModule.toBoolean()) { - apply plugin: 'com.android.application' -} else { - apply plugin: 'com.android.library' -} - -apply plugin: 'com.neenbedankt.android-apt' - -android { - compileSdkVersion rootProject.ext.compileSdkVersion - buildToolsVersion rootProject.ext.buildToolsVersion - - defaultConfig { - minSdkVersion rootProject.ext.minSdkVersion - targetSdkVersion rootProject.ext.targetSdkVersion - versionCode rootProject.ext.versionCode - versionName rootProject.ext.versionName - } - - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - } - } - - sourceSets { - main { - if (isModule.toBoolean()) { - manifest.srcFile 'src/main/debug/AndroidManifest.xml' - } else { - manifest.srcFile 'src/main/release/AndroidManifest.xml' - //release模式下排除debug文件夹中的所有Java文件 - java { - exclude 'debug/**' - } - } - } - } - //设置了resourcePrefix值后,所有的资源名必须以指定的字符串做前缀,否则会报错。 - //但是resourcePrefix这个值只能限定xml里面的资源,并不能限定图片资源,所有图片资源仍然需要手动去修改资源名。 - //resourcePrefix "girls_" -} - -dependencies { - compile fileTree(dir: 'libs', include: ['*.jar']) - compile project(':common') - //router - apt "com.github.mzule.activityrouter:compiler:$rootProject.aptCompilerVersion" -} diff --git a/girls/proguard-rules.pro b/girls/proguard-rules.pro deleted file mode 100644 index 1fa287c..0000000 --- a/girls/proguard-rules.pro +++ /dev/null @@ -1,17 +0,0 @@ -# Add project specific ProGuard rules here. -# By default, the flags in this file are appended to flags specified -# in D:\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 *; -#} diff --git a/girls/src/main/java/com/guiying/girls/Girls.java b/girls/src/main/java/com/guiying/girls/Girls.java deleted file mode 100644 index 3386507..0000000 --- a/girls/src/main/java/com/guiying/girls/Girls.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.guiying.girls; - -import com.github.mzule.activityrouter.annotation.Module; - -/** - *

类说明

- * - * @author 张华洋 2017/2/15 16:34 - * @version V1.2.0 - * @name Girls - */ -@Module("girls") -public class Girls { -} diff --git a/gradle.properties b/gradle.properties index cc07a2a..9b51cd5 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,17 +9,18 @@ # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. -org.gradle.jvmargs=-Xmx1536m +org.gradle.jvmargs=-Xmx2048m # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects + org.gradle.daemon=true org.gradle.configureondemand=true org.gradle.parallel=true -# ΪԶ(ΪÿĵԻһ) -localBuildToolsVersion=25.0.2 -localGradlePluginVersion=2.3.0 +# ֵһAndroidStudio汾һ +localGradlePluginVersion=3.0.1 # ÿθġisModuleֵҪ "Sync Project" ť -isModule=true \ No newline at end of file +# isModuleǡɿģʽ͡ģʽл +isModule=false diff --git a/keystore.properties b/keystore.properties new file mode 100644 index 0000000..dabd93e --- /dev/null +++ b/keystore.properties @@ -0,0 +1,4 @@ +storePassword=guiying712 +keyPassword=guiying712 +keyAlias=guiying712 +storeFile=/mykey.jks \ No newline at end of file diff --git a/common/.gitignore b/lib_common/.gitignore similarity index 100% rename from common/.gitignore rename to lib_common/.gitignore diff --git a/lib_common/build.gradle b/lib_common/build.gradle new file mode 100644 index 0000000..87eb2af --- /dev/null +++ b/lib_common/build.gradle @@ -0,0 +1,76 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion build_versions.target_sdk + defaultConfig { + minSdkVersion build_versions.min_sdk + targetSdkVersion build_versions.target_sdk + versionCode 1 + versionName "1.0" + } + + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + buildTypes { + release { + buildConfigField "boolean", "LOG_DEBUG", "true" + zipAlignEnabled false + shrinkResources false + minifyEnabled false + debuggable true + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + +} + +dependencies { + api fileTree(include: ['*.jar'], dir: 'libs') + // Support libraries + api deps.support.app_compat + api deps.support.v4 + api deps.support.v13 + api deps.support.design + api deps.support.cardview + api deps.support.percent + api deps.support.recyclerview + api deps.constraint_layout + + // RxJava and retrofit + api deps.rx_android + api deps.rxjava2 + api deps.retrofit.runtime + api deps.retrofit.gson + api deps.persistent_cookie + + //Dagger + api deps.dagger.runtime + api deps.dagger.android + api deps.dagger.android_support + + // other + api deps.kotlin.stdlib + api deps.event_bus + api deps.gson + api deps.permission + api deps.utils + api deps.glide + + //view + api deps.photo_view + api deps.easy_recycler + api deps.material_dialog + api deps.logger + api deps.toasty + + //router + api deps.arouter_api + + //annotationProcessor + annotationProcessor deps.dagger.android_support_compiler + annotationProcessor deps.dagger.compiler +} diff --git a/common/libs/simple-xml-core.jar b/lib_common/libs/simple-xml-core.jar similarity index 100% rename from common/libs/simple-xml-core.jar rename to lib_common/libs/simple-xml-core.jar diff --git a/lib_common/src/main/AndroidManifest.xml b/lib_common/src/main/AndroidManifest.xml new file mode 100644 index 0000000..8039311 --- /dev/null +++ b/lib_common/src/main/AndroidManifest.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_common/src/main/java/com/guiying/module/common/base/BaseActionBarActivity.java b/lib_common/src/main/java/com/guiying/module/common/base/BaseActionBarActivity.java new file mode 100644 index 0000000..85c8570 --- /dev/null +++ b/lib_common/src/main/java/com/guiying/module/common/base/BaseActionBarActivity.java @@ -0,0 +1,58 @@ +package com.guiying.module.common.base; + +import android.os.Bundle; +import android.support.annotation.Keep; +import android.support.annotation.StringRes; +import android.support.v7.app.ActionBar; + +import com.guiying.module.common.R; + +/** + * BaseActionBarActivity继承于BaseActivity,封装了actionBar的逻辑; + * 继承于ActionBarBaseActivity的Activity都将默认带有ActionBar,并且只能使用AppTheme主题; + * 只有那些ActionBar只带有Title和返回按钮的Activity方可继承 + * + * @author 张华洋 2017/3/7 18:36 + * @version V1.2.0 + * @name BaseActionBarActivity + */ +@Keep +public abstract class BaseActionBarActivity extends BaseActivity { + + /*默认的ActionBar*/ + protected ActionBar mActionBar; + + /** + * 设置默认标题id + * + * @return 标题id + */ + @StringRes + protected abstract int setTitleId(); + + + /** + * 更新标题 + * + * @param title String标题 + */ + protected void setTitle(String title) { + if (mActionBar != null) { + mActionBar.setTitle(title); + } + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + //标题栏设置 + mActionBar = getSupportActionBar(); + if (mActionBar != null) { + mActionBar.setHomeAsUpIndicator(R.drawable.ic_arrow_back); + mActionBar.setDisplayHomeAsUpEnabled(true); + mActionBar.setHomeButtonEnabled(true); + mActionBar.setTitle(setTitleId()); + } + } + +} diff --git a/lib_common/src/main/java/com/guiying/module/common/base/BaseActivity.java b/lib_common/src/main/java/com/guiying/module/common/base/BaseActivity.java new file mode 100644 index 0000000..32ffebe --- /dev/null +++ b/lib_common/src/main/java/com/guiying/module/common/base/BaseActivity.java @@ -0,0 +1,157 @@ +package com.guiying.module.common.base; + +import android.os.Bundle; +import android.support.annotation.IdRes; +import android.support.annotation.Keep; +import android.support.v7.app.ActionBar; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.Toolbar; +import android.view.View; + +import com.guiying.module.common.R; +import com.guiying.module.common.utils.Utils; + +/** + *

Activity基类

+ * + * @author 2016/12/2 17:33 + * @version V1.0.0 + * @name BaseActivity + */ +@Keep +public abstract class BaseActivity extends AppCompatActivity { + + + /** + * 封装的findViewByID方法 + */ + @SuppressWarnings("unchecked") + protected T $(@IdRes int id) { + return (T) super.findViewById(id); + } + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + ViewManager.getInstance().addActivity(this); + } + + + @Override + protected void onDestroy() { + super.onDestroy(); + ViewManager.getInstance().finishActivity(this); + } + + @Override + public boolean onSupportNavigateUp() { + onBackPressed(); + return true; + } + + + /** + * Setup the toolbar. + * + * @param toolbar toolbar + * @param hideTitle 是否隐藏Title + */ + protected void setupToolBar(Toolbar toolbar, boolean hideTitle) { + setSupportActionBar(toolbar); + ActionBar actionBar = getSupportActionBar(); + if (actionBar != null) { + actionBar.setHomeAsUpIndicator(R.drawable.ic_arrow_back); + actionBar.setDisplayHomeAsUpEnabled(true); + actionBar.setDisplayShowHomeEnabled(true); + if (hideTitle) { + //隐藏Title + actionBar.setDisplayShowTitleEnabled(false); + } + } + } + + + /** + * 添加fragment + * + * @param fragment + * @param frameId + */ + protected void addFragment(BaseFragment fragment, @IdRes int frameId) { + Utils.checkNotNull(fragment); + getSupportFragmentManager().beginTransaction() + .add(frameId, fragment, fragment.getClass().getSimpleName()) + .addToBackStack(fragment.getClass().getSimpleName()) + .commitAllowingStateLoss(); + + } + + + /** + * 替换fragment + * @param fragment + * @param frameId + */ + protected void replaceFragment(BaseFragment fragment, @IdRes int frameId) { + Utils.checkNotNull(fragment); + getSupportFragmentManager().beginTransaction() + .replace(frameId, fragment, fragment.getClass().getSimpleName()) + .addToBackStack(fragment.getClass().getSimpleName()) + .commitAllowingStateLoss(); + + } + + + /** + * 隐藏fragment + * @param fragment + */ + protected void hideFragment(BaseFragment fragment) { + Utils.checkNotNull(fragment); + getSupportFragmentManager().beginTransaction() + .hide(fragment) + .commitAllowingStateLoss(); + + } + + + /** + * 显示fragment + * @param fragment + */ + protected void showFragment(BaseFragment fragment) { + Utils.checkNotNull(fragment); + getSupportFragmentManager().beginTransaction() + .show(fragment) + .commitAllowingStateLoss(); + + } + + + /** + * 移除fragment + * @param fragment + */ + protected void removeFragment(BaseFragment fragment) { + Utils.checkNotNull(fragment); + getSupportFragmentManager().beginTransaction() + .remove(fragment) + .commitAllowingStateLoss(); + + } + + + /** + * 弹出栈顶部的Fragment + */ + protected void popFragment() { + if (getSupportFragmentManager().getBackStackEntryCount() > 1) { + getSupportFragmentManager().popBackStack(); + } else { + finish(); + } + } + + +} diff --git a/lib_common/src/main/java/com/guiying/module/common/base/BaseApplication.java b/lib_common/src/main/java/com/guiying/module/common/base/BaseApplication.java new file mode 100644 index 0000000..5c183ee --- /dev/null +++ b/lib_common/src/main/java/com/guiying/module/common/base/BaseApplication.java @@ -0,0 +1,71 @@ +package com.guiying.module.common.base; + +import android.app.Application; + +import com.guiying.module.common.utils.Utils; +import com.orhanobut.logger.LogLevel; +import com.orhanobut.logger.Logger; + +import java.util.List; + +/** + * 要想使用BaseApplication,必须在组件中实现自己的Application,并且继承BaseApplication; + * 组件中实现的Application必须在debug包中的AndroidManifest.xml中注册,否则无法使用; + * 组件的Application需置于java/debug文件夹中,不得放于主代码; + * 组件中获取Context的方法必须为:Utils.getContext(),不允许其他写法; + * + * @author 2016/12/2 17:02 + * @version V1.0.0 + * @name BaseApplication + */ +public class BaseApplication extends Application { + + public static final String ROOT_PACKAGE = "com.guiying.module"; + + private static BaseApplication sInstance; + + private List mAppDelegateList; + + + public static BaseApplication getIns() { + return sInstance; + } + + @Override + public void onCreate() { + super.onCreate(); + sInstance = this; + Logger.init("pattern").logLevel(LogLevel.FULL); + Utils.init(this); + mAppDelegateList = ClassUtils.getObjectsWithInterface(this, IApplicationDelegate.class, ROOT_PACKAGE); + for (IApplicationDelegate delegate : mAppDelegateList) { + delegate.onCreate(); + } + + } + + @Override + public void onTerminate() { + super.onTerminate(); + for (IApplicationDelegate delegate : mAppDelegateList) { + delegate.onTerminate(); + } + } + + + @Override + public void onLowMemory() { + super.onLowMemory(); + for (IApplicationDelegate delegate : mAppDelegateList) { + delegate.onLowMemory(); + } + } + + @Override + public void onTrimMemory(int level) { + super.onTrimMemory(level); + for (IApplicationDelegate delegate : mAppDelegateList) { + delegate.onTrimMemory(level); + } + } +} diff --git a/lib_common/src/main/java/com/guiying/module/common/base/BaseFragment.java b/lib_common/src/main/java/com/guiying/module/common/base/BaseFragment.java new file mode 100644 index 0000000..5ec3cb5 --- /dev/null +++ b/lib_common/src/main/java/com/guiying/module/common/base/BaseFragment.java @@ -0,0 +1,104 @@ +package com.guiying.module.common.base; + +import android.content.Context; +import android.support.annotation.IdRes; +import android.support.annotation.Keep; +import android.support.v4.app.Fragment; + +import com.guiying.module.common.utils.Utils; + +/** + *

Fragment的基类

+ * + * @author 张华洋 + * @name BaseFragment + */ +@Keep +public abstract class BaseFragment extends Fragment { + + protected BaseActivity mActivity; + + @Override + public void onAttach(Context context) { + super.onAttach(context); + this.mActivity = (BaseActivity) context; + } + + + /** + * 获取宿主Activity + * + * @return BaseActivity + */ + protected BaseActivity getHoldingActivity() { + return mActivity; + } + + + /** + * 添加fragment + * + * @param fragment + * @param frameId + */ + protected void addFragment(BaseFragment fragment, @IdRes int frameId) { + Utils.checkNotNull(fragment); + getHoldingActivity().addFragment(fragment, frameId); + + } + + + /** + * 替换fragment + * + * @param fragment + * @param frameId + */ + protected void replaceFragment(BaseFragment fragment, @IdRes int frameId) { + Utils.checkNotNull(fragment); + getHoldingActivity().replaceFragment(fragment, frameId); + } + + + /** + * 隐藏fragment + * + * @param fragment + */ + protected void hideFragment(BaseFragment fragment) { + Utils.checkNotNull(fragment); + getHoldingActivity().hideFragment(fragment); + } + + + /** + * 显示fragment + * + * @param fragment + */ + protected void showFragment(BaseFragment fragment) { + Utils.checkNotNull(fragment); + getHoldingActivity().showFragment(fragment); + } + + + /** + * 移除Fragment + * + * @param fragment + */ + protected void removeFragment(BaseFragment fragment) { + Utils.checkNotNull(fragment); + getHoldingActivity().removeFragment(fragment); + + } + + + /** + * 弹出栈顶部的Fragment + */ + protected void popFragment() { + getHoldingActivity().popFragment(); + } + +} diff --git a/lib_common/src/main/java/com/guiying/module/common/base/BasePresenter.java b/lib_common/src/main/java/com/guiying/module/common/base/BasePresenter.java new file mode 100644 index 0000000..be56ad9 --- /dev/null +++ b/lib_common/src/main/java/com/guiying/module/common/base/BasePresenter.java @@ -0,0 +1,16 @@ +package com.guiying.module.common.base; + +import android.support.annotation.Keep; + +/** + *

Presenter的基类

+ * + * @author 张华洋 + * @name BasePresenter + */ +@Keep +public interface BasePresenter { + + void start(); + +} diff --git a/lib_common/src/main/java/com/guiying/module/common/base/BaseView.java b/lib_common/src/main/java/com/guiying/module/common/base/BaseView.java new file mode 100644 index 0000000..e1b0b21 --- /dev/null +++ b/lib_common/src/main/java/com/guiying/module/common/base/BaseView.java @@ -0,0 +1,17 @@ +package com.guiying.module.common.base; + + +import android.support.annotation.Keep; + +/** + *

View接口的基类

+ * + * @author 张华洋 + * @name BaseView + */ +@Keep +public interface BaseView { + + void setPresenter(T presenter); + +} diff --git a/lib_common/src/main/java/com/guiying/module/common/base/ClassUtils.java b/lib_common/src/main/java/com/guiying/module/common/base/ClassUtils.java new file mode 100644 index 0000000..7e65de6 --- /dev/null +++ b/lib_common/src/main/java/com/guiying/module/common/base/ClassUtils.java @@ -0,0 +1,296 @@ +package com.guiying.module.common.base; + +import android.content.Context; +import android.content.SharedPreferences; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.os.Build; +import android.support.annotation.Keep; +import android.util.Log; + +import com.guiying.module.common.utils.Utils; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Enumeration; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import dalvik.system.DexFile; + +/** + * Copy from galaxy sdk ${com.alibaba.android.galaxy.utils.ClassUtils} + * Scanner, find out class with any conditions, copy from google source code. + */ +@Keep +public class ClassUtils { + private static final String TAG = "ClassUtils"; + + private static final String EXTRACTED_NAME_EXT = ".classes"; + private static final String EXTRACTED_SUFFIX = ".zip"; + + private static final String SECONDARY_FOLDER_NAME = "code_cache" + File.separator + "secondary-dexes"; + + private static final String PREFS_FILE = "multidex.version"; + private static final String KEY_DEX_NUMBER = "dex.number"; + + private static final int VM_WITH_MULTIDEX_VERSION_MAJOR = 2; + private static final int VM_WITH_MULTIDEX_VERSION_MINOR = 1; + + private static SharedPreferences getMultiDexPreferences(Context context) { + return context.getSharedPreferences(PREFS_FILE, Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB ? Context.MODE_PRIVATE : Context.MODE_PRIVATE | Context.MODE_MULTI_PROCESS); + } + + + /** + * 获取单一路径下所有实现了接口的类对象 + * + * @param context U know + * @param clazz 接口 + * @param path 包路径 + * @param U know + * @return 对象列表 + */ + public static List + getObjectsWithInterface(Context context, Class clazz, String path) { + List objectList = new ArrayList<>(); + try { + //找出所有路径中的类名,主要用于各个组件根包名一致的情况 + List classFileNames = getFileNameByPackageName(context, path); + + for (String className : classFileNames) { + Class aClass = Class.forName(className); + if (clazz.isAssignableFrom(aClass) && !clazz.equals(aClass) && !aClass.isInterface()) { + objectList.add((T) Class.forName(className).getConstructor().newInstance()); + } + } + + if (objectList.size() == 0) { + Log.e(TAG, "No files were found, check your configuration please!"); + } + } catch (Exception e) { + e.getStackTrace(); + Log.e(TAG, "getObjectsWithInterface error, " + e.getMessage()); + } + + return objectList; + } + + + /** + * 获取多路径下所有实现了接口的类对象 + * + * @param context U know + * @param clazz 接口 + * @param pathList 包路径列表 + * @param U know + * @return 对象列表 + */ + public static List getObjectsWithInterface(Context context, Class clazz, List pathList) { + List objectList = new ArrayList<>(); + try { + for (String path : pathList) { + //找出所有路径中的类名,主要用于各个组件根包名不一致的情况 + List classFileNames = getFileNameByPackageName(context, path); + + for (String className : classFileNames) { + Class aClass = Class.forName(className); + if (clazz.isAssignableFrom(aClass) && !clazz.equals(aClass) && !aClass.isInterface()) { + objectList.add((T) Class.forName(className).getConstructor().newInstance()); + } + } + } + + if (objectList.size() == 0) { + Log.e(TAG, "No files were found, check your configuration please!"); + } + } catch (Exception e) { + e.getStackTrace(); + Log.e(TAG, "getObjectsWithInterface error, " + e.getMessage()); + } + + return objectList; + } + + + /** + * 通过指定包名,扫描包下面包含的所有的ClassName + * + * @param context U know + * @param packageName 包名 + * @return 所有class的集合 + */ + public static List getFileNameByPackageName(Context context, String packageName) throws PackageManager.NameNotFoundException, IOException { + List classNames = new ArrayList<>(); + for (String path : getSourcePaths(context)) { + DexFile dexfile = null; + + try { + if (path.endsWith(EXTRACTED_SUFFIX)) { + //NOT use new DexFile(path), because it will throw "permission error in /data/dalvik-cache" + dexfile = DexFile.loadDex(path, path + ".tmp", 0); + } else { + dexfile = new DexFile(path); + } + Enumeration dexEntries = dexfile.entries(); + while (dexEntries.hasMoreElements()) { + String className = dexEntries.nextElement(); + if (className.contains(packageName)) { + classNames.add(className); + } + } + } catch (Throwable ignore) { + Log.e(TAG, "Scan map file in dex files made error.", ignore); + } finally { + if (null != dexfile) { + try { + dexfile.close(); + } catch (Throwable ignore) { + } + } + } + } + + Log.d(TAG, "Filter " + classNames.size() + " classes by packageName <" + packageName + ">"); + return classNames; + } + + /** + * get all the dex path + * + * @param context the application context + * @return all the dex path + * @throws PackageManager.NameNotFoundException Exception + * @throws IOException Exception + */ + public static List getSourcePaths(Context context) throws PackageManager.NameNotFoundException, IOException { + ApplicationInfo applicationInfo = context.getPackageManager().getApplicationInfo(context.getPackageName(), 0); + File sourceApk = new File(applicationInfo.sourceDir); + + List sourcePaths = new ArrayList<>(); + sourcePaths.add(applicationInfo.sourceDir); //add the default apk path + + //the prefix of extracted file, ie: test.classes + String extractedFilePrefix = sourceApk.getName() + EXTRACTED_NAME_EXT; + + //如果VM已经支持了MultiDex,就不要去Secondary Folder加载 Classesx.zip了,那里已经么有了 + //通过是否存在sp中的multidex.version是不准确的,因为从低版本升级上来的用户,是包含这个sp配置的 + if (!isVMMultidexCapable()) { + //the total dex numbers + int totalDexNumber = getMultiDexPreferences(context).getInt(KEY_DEX_NUMBER, 1); + File dexDir = new File(applicationInfo.dataDir, SECONDARY_FOLDER_NAME); + + for (int secondaryNumber = 2; secondaryNumber <= totalDexNumber; secondaryNumber++) { + //for each dex file, ie: test.classes2.zip, test.classes3.zip... + String fileName = extractedFilePrefix + secondaryNumber + EXTRACTED_SUFFIX; + File extractedFile = new File(dexDir, fileName); + if (extractedFile.isFile()) { + sourcePaths.add(extractedFile.getAbsolutePath()); + //we ignore the verify zip part + } else { + throw new IOException("Missing extracted secondary dex file '" + extractedFile.getPath() + "'"); + } + } + } + + if (Utils.isAppDebug()) { + // Search instant run support only debuggable + sourcePaths.addAll(tryLoadInstantRunDexFile(applicationInfo)); + } + return sourcePaths; + } + + /** + * Get instant run dex path, used to catch the branch usingApkSplits=false. + */ + private static List tryLoadInstantRunDexFile(ApplicationInfo applicationInfo) { + List instantRunSourcePaths = new ArrayList<>(); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && null != applicationInfo.splitSourceDirs) { + // add the splite apk, normally for InstantRun, and newest version. + instantRunSourcePaths.addAll(Arrays.asList(applicationInfo.splitSourceDirs)); + Log.d(TAG, "Found InstantRun support"); + } else { + try { + // This man is reflection from Google instant run sdk, he will tell me where the dex files go. + Class pathsByInstantRun = Class.forName("com.android.tools.fd.runtime.Paths"); + Method getDexFileDirectory = pathsByInstantRun.getMethod("getDexFileDirectory", String.class); + String instantRunDexPath = (String) getDexFileDirectory.invoke(null, applicationInfo.packageName); + + File instantRunFilePath = new File(instantRunDexPath); + if (instantRunFilePath.exists() && instantRunFilePath.isDirectory()) { + File[] dexFile = instantRunFilePath.listFiles(); + for (File file : dexFile) { + if (null != file && file.exists() && file.isFile() && file.getName().endsWith(".dex")) { + instantRunSourcePaths.add(file.getAbsolutePath()); + } + } + Log.d(TAG, "Found InstantRun support"); + } + + } catch (Exception e) { + Log.e(TAG, "InstantRun support error, " + e.getMessage()); + } + } + + return instantRunSourcePaths; + } + + /** + * Identifies if the current VM has a native support for multidex, meaning there is no need for + * additional installation by this library. + * + * @return true if the VM handles multidex + */ + private static boolean isVMMultidexCapable() { + boolean isMultidexCapable = false; + String vmName = null; + + try { + if (isYunOS()) { // YunOS需要特殊判断 + vmName = "'YunOS'"; + isMultidexCapable = Integer.valueOf(System.getProperty("ro.build.version.sdk")) >= 21; + } else { // 非YunOS原生Android + vmName = "'Android'"; + String versionString = System.getProperty("java.vm.version"); + if (versionString != null) { + Matcher matcher = Pattern.compile("(\\d+)\\.(\\d+)(\\.\\d+)?").matcher(versionString); + if (matcher.matches()) { + try { + int major = Integer.parseInt(matcher.group(1)); + int minor = Integer.parseInt(matcher.group(2)); + isMultidexCapable = (major > VM_WITH_MULTIDEX_VERSION_MAJOR) + || ((major == VM_WITH_MULTIDEX_VERSION_MAJOR) + && (minor >= VM_WITH_MULTIDEX_VERSION_MINOR)); + } catch (NumberFormatException ignore) { + // let isMultidexCapable be false + } + } + } + } + } catch (Exception ignore) { + + } + + Log.i(TAG, "VM with name " + vmName + (isMultidexCapable ? " has multidex support" : " does not have multidex support")); + return isMultidexCapable; + } + + /** + * 判断系统是否为YunOS系统 + */ + private static boolean isYunOS() { + try { + String version = System.getProperty("ro.yunos.version"); + String vmName = System.getProperty("java.vm.name"); + return (vmName != null && vmName.toLowerCase().contains("lemur")) + || (version != null && version.trim().length() > 0); + } catch (Exception ignore) { + return false; + } + } +} \ No newline at end of file diff --git a/lib_common/src/main/java/com/guiying/module/common/base/IApplicationDelegate.java b/lib_common/src/main/java/com/guiying/module/common/base/IApplicationDelegate.java new file mode 100644 index 0000000..1ea31b6 --- /dev/null +++ b/lib_common/src/main/java/com/guiying/module/common/base/IApplicationDelegate.java @@ -0,0 +1,23 @@ +package com.guiying.module.common.base; + +import android.support.annotation.Keep; + +/** + *

类说明

+ * + * @author 张华洋 2017/9/20 22:23 + * @version V2.8.3 + * @name ApplicationDelegate + */ +@Keep +public interface IApplicationDelegate { + + void onCreate(); + + void onTerminate(); + + void onLowMemory(); + + void onTrimMemory(int level); + +} diff --git a/lib_common/src/main/java/com/guiying/module/common/base/IViewDelegate.java b/lib_common/src/main/java/com/guiying/module/common/base/IViewDelegate.java new file mode 100644 index 0000000..3c35b8e --- /dev/null +++ b/lib_common/src/main/java/com/guiying/module/common/base/IViewDelegate.java @@ -0,0 +1,21 @@ +package com.guiying.module.common.base; + + +import android.support.annotation.Keep; +import android.view.View; + +/** + *

类说明

+ * + * @author 张华洋 2018/1/4 22:10 + * @version V2.8.3 + * @name IFragmentDelegate + */ +@Keep +public interface IViewDelegate { + + BaseFragment getFragment(String name); + + View getView(String name); + +} diff --git a/common/src/main/java/com/guiying/common/http/InfoCallback.java b/lib_common/src/main/java/com/guiying/module/common/base/InfoCallback.java similarity index 72% rename from common/src/main/java/com/guiying/common/http/InfoCallback.java rename to lib_common/src/main/java/com/guiying/module/common/base/InfoCallback.java index ec1fda9..8a5cf9b 100644 --- a/common/src/main/java/com/guiying/common/http/InfoCallback.java +++ b/lib_common/src/main/java/com/guiying/module/common/base/InfoCallback.java @@ -1,4 +1,6 @@ -package com.guiying.common.http; +package com.guiying.module.common.base; + +import android.support.annotation.Keep; /** *

数据回调接口

@@ -7,6 +9,7 @@ * @version V1.2.0 * @name InfoCallback */ +@Keep public interface InfoCallback { void onSuccess(T info); diff --git a/common/src/main/java/com/guiying/common/base/BaseApplication.java b/lib_common/src/main/java/com/guiying/module/common/base/ViewManager.java similarity index 55% rename from common/src/main/java/com/guiying/common/base/BaseApplication.java rename to lib_common/src/main/java/com/guiying/module/common/base/ViewManager.java index d0845d8..8f221a0 100644 --- a/common/src/main/java/com/guiying/common/base/BaseApplication.java +++ b/lib_common/src/main/java/com/guiying/module/common/base/ViewManager.java @@ -1,68 +1,82 @@ -package com.guiying.common.base; +package com.guiying.module.common.base; import android.app.Activity; -import android.app.ActivityManager; -import android.app.Application; import android.content.Context; +import android.support.annotation.Keep; import android.util.Log; -import com.guiying.common.utils.Utils; -import com.orhanobut.logger.LogLevel; -import com.orhanobut.logger.Logger; - +import java.util.ArrayList; +import java.util.List; import java.util.Stack; /** - * 要想使用BaseApplication,必须在组件中实现自己的Application,并且继承BaseApplication; - * 组件中实现的Application必须在debug包中的AndroidManifest.xml中注册,否则无法使用; - * 组件的Application需置于java/debug文件夹中,不得放于主代码; - * 组件中获取Context的方法必须为:Utils.getContext(),不允许其他写法; - * BaseApplication主要用来管理全局Activity; + *

* - * @author 2016/12/2 17:02 - * @version V1.0.0 - * @name BaseApplication + * @author 张华洋 2017/9/26 22:26 + * @version V1.1 + * @name ViewManager */ -public class BaseApplication extends Application { +@Keep +public class ViewManager { + + private static Stack activityStack; + private static List fragmentList; + + public static ViewManager getInstance() { + return ViewManagerHolder.sInstance; + } - private static BaseApplication sInstance; + private static class ViewManagerHolder { + private static final ViewManager sInstance = new ViewManager(); + } - private Stack activityStack; + private ViewManager() { + } - public static BaseApplication getIns() { - return sInstance; + public void addFragment(int index, BaseFragment fragment) { + if (fragmentList == null) { + fragmentList = new ArrayList<>(); + } + fragmentList.add(index, fragment); + } + + + public BaseFragment getFragment(int index) { + if (fragmentList != null) { + return fragmentList.get(index); + } + return null; } - @Override - public void onCreate() { - super.onCreate(); - sInstance = this; - Utils.init(this); - if (Utils.isAppDebug()) { - //只有debug模式才会打印日志 - Logger.init("Petrel").logLevel(LogLevel.FULL); - } else { - Logger.init("Petrel").logLevel(LogLevel.NONE); + + public List getAllFragment() { + if (fragmentList != null) { + return fragmentList; } + return null; } + /** * 添加指定Activity到堆栈 */ public void addActivity(Activity activity) { if (activityStack == null) { - activityStack = new Stack<>(); + activityStack = new Stack(); } activityStack.add(activity); } + /** * 获取当前Activity */ public Activity currentActivity() { - return activityStack.lastElement(); + Activity activity = activityStack.lastElement(); + return activity; } + /** * 结束当前Activity */ @@ -71,6 +85,7 @@ public void finishActivity() { finishActivity(activity); } + /** * 结束指定的Activity */ @@ -82,6 +97,7 @@ public void finishActivity(Activity activity) { } } + /** * 结束指定Class的Activity */ @@ -94,6 +110,7 @@ public void finishActivity(Class cls) { } } + /** * 结束全部的Activity */ @@ -106,6 +123,7 @@ public void finishAllActivity() { activityStack.clear(); } + /** * 退出应用程序 */ @@ -113,13 +131,11 @@ public void exitApp(Context context) { try { finishAllActivity(); //杀死后台进程需要在AndroidManifest中声明android.permission.KILL_BACKGROUND_PROCESSES; - ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); + android.app.ActivityManager activityManager = (android.app.ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); activityManager.killBackgroundProcesses(context.getPackageName()); - System.exit(0); + //System.exit(0); } catch (Exception e) { Log.e("ActivityManager", "app exit" + e.getMessage()); } } - - } diff --git a/lib_common/src/main/java/com/guiying/module/common/glide/ImageUtils.java b/lib_common/src/main/java/com/guiying/module/common/glide/ImageUtils.java new file mode 100644 index 0000000..6bd37ee --- /dev/null +++ b/lib_common/src/main/java/com/guiying/module/common/glide/ImageUtils.java @@ -0,0 +1,133 @@ +package com.guiying.module.common.glide; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.drawable.Drawable; +import android.view.View; +import android.widget.ImageView; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.load.engine.DiskCacheStrategy; +import com.bumptech.glide.load.resource.drawable.GlideDrawable; +import com.bumptech.glide.request.animation.GlideAnimation; +import com.bumptech.glide.request.target.GlideDrawableImageViewTarget; +import com.bumptech.glide.request.target.SimpleTarget; +import com.guiying.module.common.utils.Utils; + +/** + *

图片加载工具类

+ * + * @name ImageUtils + */ +public class ImageUtils { + + /** + * 默认加载 + */ + public static void loadImageView(String path, ImageView mImageView) { + Glide.with(mImageView.getContext()).load(path).into(mImageView); + } + + public static void loadImageWithError(String path, int errorRes, ImageView mImageView) { + Glide.with(mImageView.getContext()) + .load(path) + .crossFade() + .diskCacheStrategy(DiskCacheStrategy.SOURCE) + .error(errorRes) + .into(mImageView); + } + + /** + * 设置加载中以及加载失败图片 + */ + public static void loadImageWithLoading(String path, ImageView mImageView, int lodingImage, int errorRes) { + Glide.with(mImageView.getContext()).load(path).placeholder(lodingImage). + error(errorRes).into(mImageView); + } + + /** + * 设置加载动画 + * api也提供了几个常用的动画:比如crossFade() + */ + public static void loadImageViewAnim(String path, int anim, ImageView mImageView) { + Glide.with(mImageView.getContext()).load(path).animate(anim).into(mImageView); + } + + + /** + * 加载为bitmap + * + * @param path 图片地址 + * @param listener 回调 + */ + public static void loadBitMap(String path, final onLoadBitmap listener) { + Glide.with(Utils.getContext()).load(path).asBitmap().into(new SimpleTarget() { + + @Override + public void onResourceReady(Bitmap bitmap, GlideAnimation glideAnimation) { + listener.onReady(bitmap); + } + + @Override + public void onLoadFailed(Exception e, Drawable errorDrawable) { + listener.onFailed(); + } + }); + } + + /** + * 显示加载进度 + * + * @param path 图片地址 + * @param mImageView 图片控件 + * @param loadView 加载view + */ + public static void loadImageWithProgress(String path, final ImageView mImageView, final View loadView, int errorRes) { + Glide.with(mImageView.getContext()).load(path).error(errorRes).into(new GlideDrawableImageViewTarget(mImageView) { + @Override + public void onResourceReady(GlideDrawable resource, GlideAnimation animation) { + super.onResourceReady(resource, animation); + loadView.setVisibility(View.GONE); + } + + @Override + public void onLoadFailed(Exception e, Drawable errorDrawable) { + super.onLoadFailed(e, errorDrawable); + loadView.setVisibility(View.GONE); + } + }); + } + + /** + * 清除view上的图片 + * + * @param view 视图 + */ + public static void clearImageView(View view) { + Glide.clear(view); + } + + /** + * 清理磁盘缓存需要在子线程中执行 + */ + public static void GuideClearDiskCache(Context mContext) { + Glide.get(mContext).clearDiskCache(); + } + + /** + * 清理内存缓存可以在UI主线程中进行 + */ + public static void GuideClearMemory(Context mContext) { + Glide.get(mContext).clearMemory(); + } + + /** + * 加载bitmap回调 + */ + public interface onLoadBitmap { + void onReady(Bitmap resource); + + void onFailed(); + } + +} \ No newline at end of file diff --git a/common/src/main/java/com/guiying/common/glide/OkHttpGlideModule.java b/lib_common/src/main/java/com/guiying/module/common/glide/OkHttpGlideModule.java similarity index 98% rename from common/src/main/java/com/guiying/common/glide/OkHttpGlideModule.java rename to lib_common/src/main/java/com/guiying/module/common/glide/OkHttpGlideModule.java index ba8969a..1fedd2e 100644 --- a/common/src/main/java/com/guiying/common/glide/OkHttpGlideModule.java +++ b/lib_common/src/main/java/com/guiying/module/common/glide/OkHttpGlideModule.java @@ -1,4 +1,4 @@ -package com.guiying.common.glide; +package com.guiying.module.common.glide; import android.content.Context; diff --git a/common/src/main/java/com/guiying/common/glide/OkHttpStreamFetcher.java b/lib_common/src/main/java/com/guiying/module/common/glide/OkHttpStreamFetcher.java similarity index 95% rename from common/src/main/java/com/guiying/common/glide/OkHttpStreamFetcher.java rename to lib_common/src/main/java/com/guiying/module/common/glide/OkHttpStreamFetcher.java index 358afd3..efd1560 100644 --- a/common/src/main/java/com/guiying/common/glide/OkHttpStreamFetcher.java +++ b/lib_common/src/main/java/com/guiying/module/common/glide/OkHttpStreamFetcher.java @@ -1,10 +1,10 @@ -package com.guiying.common.glide; +package com.guiying.module.common.glide; import com.bumptech.glide.Priority; import com.bumptech.glide.load.data.DataFetcher; import com.bumptech.glide.load.model.GlideUrl; import com.bumptech.glide.util.ContentLengthInputStream; -import com.guiying.common.utils.CloseUtils; +import com.guiying.module.common.utils.CloseUtils; import java.io.IOException; import java.io.InputStream; diff --git a/common/src/main/java/com/guiying/common/glide/OkHttpUrlLoader.java b/lib_common/src/main/java/com/guiying/module/common/glide/OkHttpUrlLoader.java similarity index 98% rename from common/src/main/java/com/guiying/common/glide/OkHttpUrlLoader.java rename to lib_common/src/main/java/com/guiying/module/common/glide/OkHttpUrlLoader.java index 89f166d..c456435 100644 --- a/common/src/main/java/com/guiying/common/glide/OkHttpUrlLoader.java +++ b/lib_common/src/main/java/com/guiying/module/common/glide/OkHttpUrlLoader.java @@ -1,4 +1,4 @@ -package com.guiying.common.glide; +package com.guiying.module.common.glide; import android.content.Context; diff --git a/common/src/main/java/com/guiying/common/http/ApiService.java b/lib_common/src/main/java/com/guiying/module/common/http/ApiService.java similarity index 97% rename from common/src/main/java/com/guiying/common/http/ApiService.java rename to lib_common/src/main/java/com/guiying/module/common/http/ApiService.java index fa73d0a..895b72e 100644 --- a/common/src/main/java/com/guiying/common/http/ApiService.java +++ b/lib_common/src/main/java/com/guiying/module/common/http/ApiService.java @@ -1,4 +1,4 @@ -package com.guiying.common.http; +package com.guiying.module.common.http; import java.util.Map; diff --git a/common/src/main/java/com/guiying/common/http/DataParseUtil.java b/lib_common/src/main/java/com/guiying/module/common/http/DataParseUtil.java similarity index 98% rename from common/src/main/java/com/guiying/common/http/DataParseUtil.java rename to lib_common/src/main/java/com/guiying/module/common/http/DataParseUtil.java index dafb631..9cbc61b 100644 --- a/common/src/main/java/com/guiying/common/http/DataParseUtil.java +++ b/lib_common/src/main/java/com/guiying/module/common/http/DataParseUtil.java @@ -1,4 +1,4 @@ -package com.guiying.common.http; +package com.guiying.module.common.http; import android.text.TextUtils; diff --git a/lib_common/src/main/java/com/guiying/module/common/http/DataType.java b/lib_common/src/main/java/com/guiying/module/common/http/DataType.java new file mode 100644 index 0000000..7847996 --- /dev/null +++ b/lib_common/src/main/java/com/guiying/module/common/http/DataType.java @@ -0,0 +1,34 @@ +package com.guiying.module.common.http; + +import android.support.annotation.IntDef; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + *

服务端响应的数据类型

+ * + * @author 张华洋 2017/5/2 21:53 + * @version V1.2.0 + * @name DataType + */ +public class DataType { + + /*返回数据为String*/ + public static final int STRING = 1; + /*返回数据为xml类型*/ + public static final int XML = 2; + /*返回数据为json对象*/ + public static final int JSON_OBJECT = 3; + /*返回数据为json数组*/ + public static final int JSON_ARRAY = 4; + + /** + * 自定义一个播放器状态注解 + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({STRING, XML, JSON_OBJECT, JSON_ARRAY}) + public @interface Type { + } + +} diff --git a/common/src/main/java/com/guiying/common/http/HttpClient.java b/lib_common/src/main/java/com/guiying/module/common/http/HttpClient.java similarity index 84% rename from common/src/main/java/com/guiying/common/http/HttpClient.java rename to lib_common/src/main/java/com/guiying/module/common/http/HttpClient.java index 23c7151..2be900b 100644 --- a/common/src/main/java/com/guiying/common/http/HttpClient.java +++ b/lib_common/src/main/java/com/guiying/module/common/http/HttpClient.java @@ -1,16 +1,17 @@ -package com.guiying.common.http; +package com.guiying.module.common.http; +import android.support.annotation.NonNull; import android.text.TextUtils; import com.franmontiel.persistentcookiejar.ClearableCookieJar; import com.franmontiel.persistentcookiejar.PersistentCookieJar; import com.franmontiel.persistentcookiejar.cache.SetCookieCache; import com.franmontiel.persistentcookiejar.persistence.SharedPrefsCookiePersistor; -import com.guiying.common.R; -import com.guiying.common.utils.NetworkUtils; -import com.guiying.common.utils.StringUtils; -import com.guiying.common.utils.ToastUtils; -import com.guiying.common.utils.Utils; +import com.guiying.module.common.R; +import com.guiying.module.common.utils.NetworkUtils; +import com.guiying.module.common.utils.StringUtils; +import com.guiying.module.common.utils.ToastUtils; +import com.guiying.module.common.utils.Utils; import com.orhanobut.logger.Logger; import java.io.IOException; @@ -37,15 +38,8 @@ public class HttpClient { /*The certificate's password*/ - private static final String STORE_PASS = "4444444"; - /*返回数据为String*/ - public static final int STRING = 0; - /*返回数据为json对象*/ - public static final int OBJECT = 1; - /*返回数据为json数组*/ - public static final int ARRAY = 2; - /*返回数据为xml类型*/ - public static final int XML = 3; + private static final String STORE_PASS = "6666666"; + private static final String STORE_ALIAS = "666666"; /*用户设置的BASE_URL*/ private static String BASE_URL = ""; /*本地使用的baseUrl*/ @@ -74,11 +68,11 @@ private static class HttpClientHolder { private HttpClient() { ClearableCookieJar cookieJar = new PersistentCookieJar(new SetCookieCache(), new SharedPrefsCookiePersistor(Utils.getContext())); - //HttpsUtil.SSLParams sslParams = HttpsUtil.getSslSocketFactory(Utils.getContext(), new int[0], , STORE_PASS); + //HttpsUtil.SSLParams sslParams = HttpsUtil.getSslSocketFactory(Utils.getContext(), R.raw.cer,STORE_PASS , STORE_ALIAS); okHttpClient = new OkHttpClient.Builder() .connectTimeout(10000L, TimeUnit.MILLISECONDS) //.sslSocketFactory(sslParams.sSLSocketFactory, sslParams.trustManager) - .hostnameVerifier(HttpsUtil.getHostnameVerifier()) + // .hostnameVerifier(HttpsUtil.getHostnameVerifier()) .addInterceptor(new LoggerInterceptor(null, true)) .cookieJar(cookieJar) .build(); @@ -146,8 +140,8 @@ public void onResponse(Call call, Response response) if (200 == response.code()) { try { String result = response.body().string(); - parseJson(result, builder.clazz, builder.bodyType, onResultListener); - } catch (IOException e) { + parseData(result, builder.clazz, builder.bodyType, onResultListener); + } catch (IOException | IllegalStateException e) { e.printStackTrace(); } } @@ -234,8 +228,9 @@ public static final class Builder { private String url; private Object tag; private Map params = new HashMap<>(); - /*返回数据的类型*/ - private int bodyType = STRING; + /*返回数据的类型,默认是string类型*/ + @DataType.Type + private int bodyType = DataType.STRING; /*解析类*/ private Class clazz; @@ -254,7 +249,7 @@ public Builder baseUrl(String baseUrl) { /** * 除baseUrl以外的部分, - * 例如:"msp/mobile/login" + * 例如:"mobile/login" * * @param url path路径 */ @@ -285,13 +280,13 @@ public Builder params(String key, String value) { } /** - * 响应体类型设置 + * 响应体类型设置,如果要响应体类型为STRING,请不要使用这个方法 * - * @param bodyType 响应体类型,分别为STRING,OBJECT,ARRAY,XML + * @param bodyType 响应体类型,分别:STRING,JSON_OBJECT,JSON_ARRAY,XML * @param clazz 指定的解析类 * @param 解析类 */ - public Builder bodyType(int bodyType, Class clazz) { + public Builder bodyType(@DataType.Type int bodyType, @NonNull Class clazz) { this.bodyType = bodyType; this.clazz = clazz; return this; @@ -308,19 +303,27 @@ public HttpClient build() { } } + /** + * 数据解析方法 + * + * @param data 要解析的数据 + * @param clazz 解析类 + * @param bodyType 解析数据类型 + * @param onResultListener 回调方数据接口 + */ @SuppressWarnings("unchecked") - private void parseJson(String data, Class clazz, int bodyType, OnResultListener onResultListener) { + private void parseData(String data, Class clazz, @DataType.Type int bodyType, OnResultListener onResultListener) { switch (bodyType) { - case STRING: + case DataType.STRING: onResultListener.onSuccess(data); break; - case OBJECT: + case DataType.JSON_OBJECT: onResultListener.onSuccess(DataParseUtil.parseObject(data, clazz)); break; - case ARRAY: - onResultListener.onSuccess(DataParseUtil.parseToList(data, clazz)); + case DataType.JSON_ARRAY: + onResultListener.onSuccess(DataParseUtil.parseToArrayList(data, clazz)); break; - case XML: + case DataType.XML: onResultListener.onSuccess(DataParseUtil.parseXml(data, clazz)); break; default: diff --git a/lib_common/src/main/java/com/guiying/module/common/http/HttpsUtils.java b/lib_common/src/main/java/com/guiying/module/common/http/HttpsUtils.java new file mode 100644 index 0000000..314d6ce --- /dev/null +++ b/lib_common/src/main/java/com/guiying/module/common/http/HttpsUtils.java @@ -0,0 +1,269 @@ +package com.guiying.module.common.http; + +import android.content.Context; +import android.support.annotation.RawRes; +import android.text.TextUtils; + +import com.guiying.module.common.utils.CloseUtils; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.InetAddress; +import java.net.Socket; +import java.security.InvalidKeyException; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.SecureRandom; +import java.security.SignatureException; +import java.security.UnrecoverableKeyException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509TrustManager; + +/** + *

Https证书校验工具类

+ * + * @author 张华洋 2017/5/11 16:14 + * @version V1.2.0 + * @name HttpsUtils + */ +public class HttpsUtils { + + + public static class SSLParams { + public SSLSocketFactory sSLSocketFactory; + public X509TrustManager trustManager; + } + + /** + * @param context 上下文 + * @param bksFileId "XXX.bks"文件(文件位置res/raw/XXX.bks) + * @param password The certificate's password. + * @return SSLParams + */ + public static SSLParams getSslSocketFactory(Context context, @RawRes int bksFileId, String password, String alias) { + if (context == null) { + throw new NullPointerException("context == null"); + } + if (TextUtils.isEmpty(password) || TextUtils.isEmpty(alias)) { + throw new NullPointerException("password == null or alias == null!"); + } + SSLParams sslParams = new SSLParams(); + try { + // 创建一个BKS类型的KeyStore,存储我们信任的证书 + KeyStore clientKeyStore = KeyStore.getInstance("BKS"); + clientKeyStore.load(context.getResources().openRawResource(bksFileId), password.toCharArray()); + //通过alias直接从密钥库中读取证书 + Certificate rootCA = clientKeyStore.getCertificate(alias); + // Turn it to X509 format. + InputStream certInput = new ByteArrayInputStream(rootCA.getEncoded()); + X509Certificate serverCert = (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(certInput); + //关闭流 + CloseUtils.closeIO(certInput); + + TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + //用我们之前的keyStore实例初始化TrustManagerFactory,这样trustManagerFactory就会信任keyStore中的证书 + trustManagerFactory.init(clientKeyStore); + + KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + keyManagerFactory.init(clientKeyStore, password.toCharArray()); + + X509TrustManager x509TrustManager = new SafeTrustManager(serverCert); + + //创建TLS类型的SSLContext对象,that uses our TrustManager + SSLContext sslContext = SSLContext.getInstance("TLS"); + + //用上面得到的trustManagers初始化SSLContext,这样sslContext就会信任keyStore中的证书 + sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), new SecureRandom()); + + //Android 4.X 对TLS1.1、TLS1.2的支持 + sslParams.sSLSocketFactory = new Tls12SocketFactory(sslContext.getSocketFactory()); + sslParams.trustManager = x509TrustManager; + return sslParams; + } catch (NoSuchAlgorithmException | KeyManagementException | KeyStoreException | UnrecoverableKeyException | IOException | CertificateException e) { + throw new AssertionError(e); + } + } + + /** + * 不做证书校验,信任所有证书 + */ + public static SSLParams getSslSocketFactoryUnsafe() { + SSLParams sslParams = new SSLParams(); + try { + X509TrustManager x509TrustManager = new UnSafeTrustManager(); + + //创建TLS类型的SSLContext对象,that uses our TrustManager + SSLContext sslContext = SSLContext.getInstance("TLS"); + + //用上面得到的trustManagers初始化SSLContext,这样sslContext就会信任keyStore中的证书 + sslContext.init(null, new TrustManager[]{x509TrustManager}, null); + + //Android 4.X 对TLS1.1、TLS1.2的支持 + sslParams.sSLSocketFactory = new Tls12SocketFactory(sslContext.getSocketFactory()); + sslParams.trustManager = x509TrustManager; + return sslParams; + } catch (NoSuchAlgorithmException | KeyManagementException e) { + throw new AssertionError(e); + } + } + + + /** + * 主机名校验方法,请把”192.168.0.10”换成你们公司的主机IP: + */ + public static HostnameVerifier getHostnameVerifier() { + return new HostnameVerifier() { + @Override + public boolean verify(String hostname, SSLSession session) { + if ("192.168.0.10".equals(hostname)) { + return true; + } else { + HostnameVerifier hv = HttpsURLConnection.getDefaultHostnameVerifier(); + return hv.verify(hostname, session); + } + } + }; + } + + + /** + * 对服务器证书域名进行强校验 + */ + private static class SafeTrustManager implements X509TrustManager { + private X509Certificate mCertificate; + + private SafeTrustManager(X509Certificate serverCert) { + mCertificate = serverCert; + } + + @Override + public void checkClientTrusted(X509Certificate[] x509Certificates, String authType) throws CertificateException { + + } + + @Override + public void checkServerTrusted(X509Certificate[] x509Certificates, String authType) throws CertificateException { + if (x509Certificates == null) { + throw new IllegalArgumentException("Check Server x509Certificates is null"); + } + + if (x509Certificates.length < 0) { + throw new IllegalArgumentException("Check Server x509Certificates is empty"); + } + + try { + for (X509Certificate cert : x509Certificates) { + // Make sure that it hasn't expired. + cert.checkValidity(); + //和App预埋的证书做对比 + cert.verify(mCertificate.getPublicKey()); + } + } catch (NoSuchAlgorithmException | InvalidKeyException | NoSuchProviderException | SignatureException e) { + e.printStackTrace(); + } + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[0]; + } + } + + + /** + * 客户端不对证书做任何验证的做法有很大的安全漏洞。 + */ + private static class UnSafeTrustManager implements X509TrustManager { + + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType) + throws CertificateException { + } + + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType) + throws CertificateException { + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[]{}; + } + } + + + /** + * 自定义SSLSocketFactory ,实现Android 4.X 对TLSv1.1、TLSv1.2的支持 + */ + private static class Tls12SocketFactory extends SSLSocketFactory { + + private static final String[] TLS_SUPPORT_VERSION = {"TLSv1.1", "TLSv1.2"}; + + final SSLSocketFactory delegate; + + private Tls12SocketFactory(SSLSocketFactory base) { + this.delegate = base; + } + + @Override + public String[] getDefaultCipherSuites() { + return delegate.getDefaultCipherSuites(); + } + + @Override + public String[] getSupportedCipherSuites() { + return delegate.getSupportedCipherSuites(); + } + + @Override + public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException { + return patch(delegate.createSocket(s, host, port, autoClose)); + } + + @Override + public Socket createSocket(String host, int port) throws IOException { + return patch(delegate.createSocket(host, port)); + } + + @Override + public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException { + return patch(delegate.createSocket(host, port, localHost, localPort)); + } + + @Override + public Socket createSocket(InetAddress host, int port) throws IOException { + return patch(delegate.createSocket(host, port)); + } + + @Override + public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException { + return patch(delegate.createSocket(address, port, localAddress, localPort)); + } + + private Socket patch(Socket s) { + //代理SSLSocketFactory在创建一个Socket连接的时候,会设置Socket的可用的TLS版本。 + if (s instanceof SSLSocket) { + ((SSLSocket) s).setEnabledProtocols(TLS_SUPPORT_VERSION); + } + return s; + } + } + +} diff --git a/common/src/main/java/com/guiying/common/http/LoggerInterceptor.java b/lib_common/src/main/java/com/guiying/module/common/http/LoggerInterceptor.java similarity index 99% rename from common/src/main/java/com/guiying/common/http/LoggerInterceptor.java rename to lib_common/src/main/java/com/guiying/module/common/http/LoggerInterceptor.java index 46cbff8..16d0660 100644 --- a/common/src/main/java/com/guiying/common/http/LoggerInterceptor.java +++ b/lib_common/src/main/java/com/guiying/module/common/http/LoggerInterceptor.java @@ -1,4 +1,4 @@ -package com.guiying.common.http; +package com.guiying.module.common.http; import android.text.TextUtils; diff --git a/common/src/main/java/com/guiying/common/http/OnResultListener.java b/lib_common/src/main/java/com/guiying/module/common/http/OnResultListener.java similarity index 94% rename from common/src/main/java/com/guiying/common/http/OnResultListener.java rename to lib_common/src/main/java/com/guiying/module/common/http/OnResultListener.java index 6274b58..527f5f0 100644 --- a/common/src/main/java/com/guiying/common/http/OnResultListener.java +++ b/lib_common/src/main/java/com/guiying/module/common/http/OnResultListener.java @@ -1,4 +1,4 @@ -package com.guiying.common.http; +package com.guiying.module.common.http; /** *

在Retrofit中接口会导致泛型擦除,所以这里回调使用Class

diff --git a/common/src/main/java/com/guiying/common/utils/CloseUtils.java b/lib_common/src/main/java/com/guiying/module/common/utils/CloseUtils.java similarity index 96% rename from common/src/main/java/com/guiying/common/utils/CloseUtils.java rename to lib_common/src/main/java/com/guiying/module/common/utils/CloseUtils.java index dae8eca..336cde0 100644 --- a/common/src/main/java/com/guiying/common/utils/CloseUtils.java +++ b/lib_common/src/main/java/com/guiying/module/common/utils/CloseUtils.java @@ -1,4 +1,4 @@ -package com.guiying.common.utils; +package com.guiying.module.common.utils; import java.io.Closeable; import java.io.IOException; diff --git a/common/src/main/java/com/guiying/common/utils/NetworkUtils.java b/lib_common/src/main/java/com/guiying/module/common/utils/NetworkUtils.java similarity index 98% rename from common/src/main/java/com/guiying/common/utils/NetworkUtils.java rename to lib_common/src/main/java/com/guiying/module/common/utils/NetworkUtils.java index 842a52e..e788077 100644 --- a/common/src/main/java/com/guiying/common/utils/NetworkUtils.java +++ b/lib_common/src/main/java/com/guiying/module/common/utils/NetworkUtils.java @@ -1,4 +1,4 @@ -package com.guiying.common.utils; +package com.guiying.module.common.utils; import android.content.Context; import android.content.Intent; @@ -144,7 +144,7 @@ public static boolean is4G() { * @return {@code true}: 是
{@code false}: 否 */ public static boolean getWifiEnabled() { - WifiManager wifiManager = (WifiManager) Utils.getContext().getSystemService(Context.WIFI_SERVICE); + WifiManager wifiManager = (WifiManager) Utils.getContext().getApplicationContext().getSystemService(Context.WIFI_SERVICE); return wifiManager.isWifiEnabled(); } @@ -155,7 +155,7 @@ public static boolean getWifiEnabled() { * @param enabled {@code true}: 打开
{@code false}: 关闭 */ public static void setWifiEnabled(boolean enabled) { - WifiManager wifiManager = (WifiManager) Utils.getContext().getSystemService(Context.WIFI_SERVICE); + WifiManager wifiManager = (WifiManager) Utils.getContext().getApplicationContext().getSystemService(Context.WIFI_SERVICE); if (enabled) { if (!wifiManager.isWifiEnabled()) { wifiManager.setWifiEnabled(true); diff --git a/lib_common/src/main/java/com/guiying/module/common/utils/ScreenLockUtil.java b/lib_common/src/main/java/com/guiying/module/common/utils/ScreenLockUtil.java new file mode 100644 index 0000000..d85c106 --- /dev/null +++ b/lib_common/src/main/java/com/guiying/module/common/utils/ScreenLockUtil.java @@ -0,0 +1,84 @@ +package com.guiying.module.common.utils; + +import android.app.Activity; +import android.app.KeyguardManager; +import android.app.KeyguardManager.KeyguardLock; +import android.content.Context; +import android.os.PowerManager; +import android.os.PowerManager.WakeLock; +import android.util.Log; + +import java.util.HashMap; + +/** + * 用于保持屏幕高亮的工具 + */ +public class ScreenLockUtil { + private static final String TAG = "ScreenLockUtil"; + + private ScreenLockUtil() { + throw new UnsupportedOperationException("cannot be instantiated"); + } + + static private HashMap mWakeLockArray = new HashMap<>(); + static private HashMap mIsUnlockArray = new HashMap<>(); + + + /** + * 保持屏幕常亮 + * + * @param activity you know + */ + public static void keepScreenOn(Activity activity) { + WakeLock wakeLock = mWakeLockArray.get(activity); + if (wakeLock == null) { + PowerManager powerManager = (PowerManager) activity.getSystemService(Context.POWER_SERVICE); + wakeLock = powerManager.newWakeLock(PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.FULL_WAKE_LOCK, + activity.getClass().getName()); + } + + if (!wakeLock.isHeld()) { + wakeLock.acquire(); + } + + mWakeLockArray.put(activity, wakeLock); + + cancelLockScreen(activity); + + Log.i(TAG, "开启屏幕常亮"); + } + + + /** + * 取消屏幕常亮 + * + * @param activity you know + */ + public static void cancelKeepScreen(Activity activity) { + WakeLock wakeLock = mWakeLockArray.get(activity); + if (wakeLock != null) { + if (wakeLock.isHeld()) { + wakeLock.release(); + } + } + + Log.i(TAG, "取消屏幕常亮"); + } + + /** + * 取消锁屏限制 + * + * @param activity you know + */ + private static void cancelLockScreen(Activity activity) { + Boolean isUnlock = mIsUnlockArray.get(activity); + if (isUnlock != null && isUnlock) { + return; + } + KeyguardManager mKeyguardManager = (KeyguardManager) activity.getSystemService(Context.KEYGUARD_SERVICE); + KeyguardLock mKeyguardLock = mKeyguardManager.newKeyguardLock(activity.getClass().getName()); + mKeyguardLock.disableKeyguard(); + + mIsUnlockArray.put(activity, true); + } +} diff --git a/common/src/main/java/com/guiying/common/utils/ShellUtils.java b/lib_common/src/main/java/com/guiying/module/common/utils/ShellUtils.java similarity index 99% rename from common/src/main/java/com/guiying/common/utils/ShellUtils.java rename to lib_common/src/main/java/com/guiying/module/common/utils/ShellUtils.java index 138f7d5..ff326cc 100644 --- a/common/src/main/java/com/guiying/common/utils/ShellUtils.java +++ b/lib_common/src/main/java/com/guiying/module/common/utils/ShellUtils.java @@ -1,4 +1,4 @@ -package com.guiying.common.utils; +package com.guiying.module.common.utils; import java.io.BufferedReader; import java.io.DataOutputStream; diff --git a/common/src/main/java/com/guiying/common/utils/StringUtils.java b/lib_common/src/main/java/com/guiying/module/common/utils/StringUtils.java similarity index 99% rename from common/src/main/java/com/guiying/common/utils/StringUtils.java rename to lib_common/src/main/java/com/guiying/module/common/utils/StringUtils.java index ccfbd93..e09c3ae 100644 --- a/common/src/main/java/com/guiying/common/utils/StringUtils.java +++ b/lib_common/src/main/java/com/guiying/module/common/utils/StringUtils.java @@ -1,4 +1,4 @@ -package com.guiying.common.utils; +package com.guiying.module.common.utils; /** * 字符串相关工具类 diff --git a/common/src/main/java/com/guiying/common/utils/ToastUtils.java b/lib_common/src/main/java/com/guiying/module/common/utils/ToastUtils.java similarity index 96% rename from common/src/main/java/com/guiying/common/utils/ToastUtils.java rename to lib_common/src/main/java/com/guiying/module/common/utils/ToastUtils.java index 61e09e4..1fd0cdb 100644 --- a/common/src/main/java/com/guiying/common/utils/ToastUtils.java +++ b/lib_common/src/main/java/com/guiying/module/common/utils/ToastUtils.java @@ -1,8 +1,10 @@ -package com.guiying.common.utils; +package com.guiying.module.common.utils; import android.os.Handler; import android.os.Looper; import android.support.annotation.StringRes; +import android.view.Gravity; +import android.widget.TextView; import android.widget.Toast; /** @@ -263,6 +265,9 @@ private static void showToast(CharSequence text, int duration) { if (isJumpWhenMore) cancelToast(); if (sToast == null) { sToast = Toast.makeText(Utils.getContext(), text, duration); + TextView tv = (TextView) sToast.getView().findViewById(android.R.id.message); + tv.setTextSize(18); + sToast.setGravity(Gravity.CENTER, 0, 0); } else { sToast.setText(text); sToast.setDuration(duration); diff --git a/common/src/main/java/com/guiying/common/utils/Utils.java b/lib_common/src/main/java/com/guiying/module/common/utils/Utils.java similarity index 71% rename from common/src/main/java/com/guiying/common/utils/Utils.java rename to lib_common/src/main/java/com/guiying/module/common/utils/Utils.java index 6c8b104..a06d64d 100644 --- a/common/src/main/java/com/guiying/common/utils/Utils.java +++ b/lib_common/src/main/java/com/guiying/module/common/utils/Utils.java @@ -1,4 +1,5 @@ -package com.guiying.common.utils; +package com.guiying.module.common.utils; + import android.app.Activity; import android.content.Context; @@ -7,6 +8,9 @@ import android.content.pm.PackageManager; import android.support.annotation.NonNull; import android.support.annotation.StringRes; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentTransaction; import android.view.View; /** @@ -87,4 +91,26 @@ public static boolean isAppDebug() { } } + + /** + * The {@code fragment} is added to the container view with id {@code frameId}. The operation is + * performed by the {@code fragmentManager}. + */ + public static void addFragmentToActivity(@NonNull FragmentManager fragmentManager, + @NonNull Fragment fragment, int frameId) { + checkNotNull(fragmentManager); + checkNotNull(fragment); + FragmentTransaction transaction = fragmentManager.beginTransaction(); + transaction.add(frameId, fragment); + transaction.commit(); + } + + + public static T checkNotNull(T obj) { + if (obj == null) { + throw new NullPointerException(); + } + return obj; + } + } \ No newline at end of file diff --git a/lib_common/src/main/java/com/guiying/module/common/widget/HackyViewPager.java b/lib_common/src/main/java/com/guiying/module/common/widget/HackyViewPager.java new file mode 100644 index 0000000..a9ace60 --- /dev/null +++ b/lib_common/src/main/java/com/guiying/module/common/widget/HackyViewPager.java @@ -0,0 +1,33 @@ +package com.guiying.module.common.widget; + +import android.content.Context; +import android.support.v4.view.ViewPager; +import android.util.AttributeSet; +import android.view.MotionEvent; + +/** + *

解决图片缩放崩溃的问题

+ * @name HackyViewPager + * @author 张华洋 2017/9/27 10:10 + * @version V1.1 + */ +public class HackyViewPager extends ViewPager { + + public HackyViewPager(Context context) { + super(context); + } + + public HackyViewPager(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + try { + return super.onInterceptTouchEvent(ev); + } catch (IllegalArgumentException | ArrayIndexOutOfBoundsException e) { + e.printStackTrace(); + } + return false; + } +} diff --git a/lib_common/src/main/java/com/guiying/module/common/widget/NoScrollViewPager.java b/lib_common/src/main/java/com/guiying/module/common/widget/NoScrollViewPager.java new file mode 100644 index 0000000..be8f2b9 --- /dev/null +++ b/lib_common/src/main/java/com/guiying/module/common/widget/NoScrollViewPager.java @@ -0,0 +1,41 @@ +package com.guiying.module.common.widget; + +import android.content.Context; +import android.support.v4.view.ViewPager; +import android.util.AttributeSet; +import android.view.MotionEvent; + +/** + *

可以禁止滑动翻页的ViewPager

+ * + * @author 张华洋 2017/9/27 10:10 + * @version V1.1 + * @name NoScrollViewPager + */ +public class NoScrollViewPager extends ViewPager { + + private boolean isPagingEnabled = true; + + public NoScrollViewPager(Context context) { + super(context); + } + + public NoScrollViewPager(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + return this.isPagingEnabled && super.onTouchEvent(event); + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent event) { + return this.isPagingEnabled && super.onInterceptTouchEvent(event); + } + + public void setPagerEnabled(boolean b) { + this.isPagingEnabled = b; + } + +} diff --git a/lib_common/src/main/res/drawable-xxhdpi/ic_arrow_back.png b/lib_common/src/main/res/drawable-xxhdpi/ic_arrow_back.png new file mode 100644 index 0000000..38c9a6d Binary files /dev/null and b/lib_common/src/main/res/drawable-xxhdpi/ic_arrow_back.png differ diff --git a/common/src/main/res/drawable/shape_loading_bg.xml b/lib_common/src/main/res/drawable/shape_loading_bg.xml similarity index 100% rename from common/src/main/res/drawable/shape_loading_bg.xml rename to lib_common/src/main/res/drawable/shape_loading_bg.xml diff --git a/common/src/main/res/layout/layout_load_error.xml b/lib_common/src/main/res/layout/layout_load_error.xml similarity index 100% rename from common/src/main/res/layout/layout_load_error.xml rename to lib_common/src/main/res/layout/layout_load_error.xml diff --git a/common/src/main/res/layout/layout_load_more.xml b/lib_common/src/main/res/layout/layout_load_more.xml similarity index 72% rename from common/src/main/res/layout/layout_load_more.xml rename to lib_common/src/main/res/layout/layout_load_more.xml index 46425fa..b6c5d09 100644 --- a/common/src/main/res/layout/layout_load_more.xml +++ b/lib_common/src/main/res/layout/layout_load_more.xml @@ -7,14 +7,14 @@ android:layout_height="50dp"> + android:layout_width="30dp" + android:layout_height="30dp" /> diff --git a/common/src/main/res/layout/layout_load_no_more.xml b/lib_common/src/main/res/layout/layout_load_no_more.xml similarity index 100% rename from common/src/main/res/layout/layout_load_no_more.xml rename to lib_common/src/main/res/layout/layout_load_no_more.xml diff --git a/common/src/main/res/layout/layout_load_progress.xml b/lib_common/src/main/res/layout/layout_load_progress.xml similarity index 100% rename from common/src/main/res/layout/layout_load_progress.xml rename to lib_common/src/main/res/layout/layout_load_progress.xml diff --git a/common/src/main/res/layout/layout_view_empty.xml b/lib_common/src/main/res/layout/layout_view_empty.xml similarity index 100% rename from common/src/main/res/layout/layout_view_empty.xml rename to lib_common/src/main/res/layout/layout_view_empty.xml diff --git a/common/src/main/res/layout/progress_dialog.xml b/lib_common/src/main/res/layout/progress_dialog.xml similarity index 100% rename from common/src/main/res/layout/progress_dialog.xml rename to lib_common/src/main/res/layout/progress_dialog.xml diff --git a/common/src/main/res/layout/toolbar.xml b/lib_common/src/main/res/layout/toolbar.xml similarity index 100% rename from common/src/main/res/layout/toolbar.xml rename to lib_common/src/main/res/layout/toolbar.xml diff --git a/common/src/main/res/mipmap-xxhdpi/ic_launcher.jpg b/lib_common/src/main/res/mipmap-xxhdpi/ic_launcher.jpg similarity index 100% rename from common/src/main/res/mipmap-xxhdpi/ic_launcher.jpg rename to lib_common/src/main/res/mipmap-xxhdpi/ic_launcher.jpg diff --git a/common/src/main/res/values-v21/styles.xml b/lib_common/src/main/res/values-v21/styles.xml similarity index 100% rename from common/src/main/res/values-v21/styles.xml rename to lib_common/src/main/res/values-v21/styles.xml diff --git a/common/src/main/res/values/colors.xml b/lib_common/src/main/res/values/colors.xml similarity index 100% rename from common/src/main/res/values/colors.xml rename to lib_common/src/main/res/values/colors.xml diff --git a/common/src/main/res/values/dimens.xml b/lib_common/src/main/res/values/dimens.xml similarity index 100% rename from common/src/main/res/values/dimens.xml rename to lib_common/src/main/res/values/dimens.xml diff --git a/common/src/main/res/values/strings.xml b/lib_common/src/main/res/values/strings.xml similarity index 100% rename from common/src/main/res/values/strings.xml rename to lib_common/src/main/res/values/strings.xml diff --git a/common/src/main/res/values/styles.xml b/lib_common/src/main/res/values/styles.xml similarity index 100% rename from common/src/main/res/values/styles.xml rename to lib_common/src/main/res/values/styles.xml diff --git a/main/build.gradle b/main/build.gradle deleted file mode 100644 index 7fd1812..0000000 --- a/main/build.gradle +++ /dev/null @@ -1,50 +0,0 @@ -if (isModule.toBoolean()) { - apply plugin: 'com.android.application' -} else { - apply plugin: 'com.android.library' -} - -apply plugin: 'com.neenbedankt.android-apt' - -android { - compileSdkVersion rootProject.ext.compileSdkVersion - buildToolsVersion rootProject.ext.buildToolsVersion - - defaultConfig { - minSdkVersion rootProject.ext.minSdkVersion - targetSdkVersion rootProject.ext.targetSdkVersion - versionCode rootProject.ext.versionCode - versionName rootProject.ext.versionName - } - - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - } - } - - sourceSets { - main { - if (isModule.toBoolean()) { - manifest.srcFile 'src/main/debug/AndroidManifest.xml' - } else { - manifest.srcFile 'src/main/release/AndroidManifest.xml' - //release模式下排除debug文件夹中的所有Java文件 - java { - exclude 'debug/**' - } - } - } - } - //设置了resourcePrefix值后,所有的资源名必须以指定的字符串做前缀,否则会报错。 - //但是resourcePrefix这个值只能限定xml里面的资源,并不能限定图片资源,所有图片资源仍然需要手动去修改资源名。 - //resourcePrefix "girls_" -} - -dependencies { - compile fileTree(dir: 'libs', include: ['*.jar']) - compile project(':common') - //router - apt "com.github.mzule.activityrouter:compiler:$rootProject.aptCompilerVersion" -} diff --git a/main/proguard-rules.pro b/main/proguard-rules.pro deleted file mode 100644 index c341b8b..0000000 --- a/main/proguard-rules.pro +++ /dev/null @@ -1,25 +0,0 @@ -# Add project specific ProGuard rules here. -# By default, the flags in this file are appended to flags specified -# in D:\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 diff --git a/main/src/main/java/com/guiying/main/Main.java b/main/src/main/java/com/guiying/main/Main.java deleted file mode 100644 index 87e625b..0000000 --- a/main/src/main/java/com/guiying/main/Main.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.guiying.main; - -import com.github.mzule.activityrouter.annotation.Module; - -/** - *

声明主要组件

- *

- * 这个组件是应用默认启动的组件 - * - * @author 张华洋 2017/4/1 12:39 - * @version V1.2.0 - * @name Main - */ - -@Module("main") -public class Main { -} diff --git a/main/src/main/java/com/guiying/main/MainActivity.java b/main/src/main/java/com/guiying/main/MainActivity.java deleted file mode 100644 index 8110108..0000000 --- a/main/src/main/java/com/guiying/main/MainActivity.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.guiying.main; - -import android.os.Bundle; -import android.support.design.widget.Snackbar; -import android.view.KeyEvent; -import android.view.View; -import android.widget.Button; - -import com.github.mzule.activityrouter.router.Routers; -import com.guiying.common.base.BaseActivity; -import com.guiying.common.base.BaseApplication; - -public class MainActivity extends BaseActivity implements View.OnClickListener { - - - private long exitTime = 0; - - protected Button newsButton; - protected Button girlsButton; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - newsButton = (Button) findViewById(R.id.news_button); - newsButton.setOnClickListener(MainActivity.this); - girlsButton = (Button) findViewById(R.id.girls_button); - girlsButton.setOnClickListener(MainActivity.this); - } - - @Override - public void onClick(View view) { - if (view.getId() == R.id.news_button) { - Routers.open(MainActivity.this, "module://news"); - } else if (view.getId() == R.id.girls_button) { - Routers.open(MainActivity.this, "module://girls"); - } - } - - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN) { - //两秒之内按返回键就会退出 - if ((System.currentTimeMillis() - exitTime) > 2000) { - Snackbar.make(girlsButton, getString(R.string.app_exit_hint), Snackbar.LENGTH_LONG).show(); - exitTime = System.currentTimeMillis(); - } else { - BaseApplication.getIns().exitApp(this); - } - return true; - } - return super.onKeyDown(keyCode, event); - } - -} diff --git a/main/src/main/res/values/strings.xml b/main/src/main/res/values/strings.xml deleted file mode 100644 index 1c3948f..0000000 --- a/main/src/main/res/values/strings.xml +++ /dev/null @@ -1,6 +0,0 @@ - - main组件 - - 再按一次退出程序哦~ - - diff --git a/app/.gitignore b/module_app/.gitignore similarity index 100% rename from app/.gitignore rename to module_app/.gitignore diff --git a/module_app/build.gradle b/module_app/build.gradle new file mode 100644 index 0000000..2776c5c --- /dev/null +++ b/module_app/build.gradle @@ -0,0 +1,84 @@ +apply plugin: 'com.android.application' + +// Create a variable called keystorePropertiesFile, and initialize it to your +// keystore.properties file, in the rootProject folder. +def keystorePropertiesFile = rootProject.file("keystore.properties") +// Initialize a new Properties() object called keystoreProperties. +def keystoreProperties = new Properties() +// Load your keystore.properties file into the keystoreProperties object. +keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) + +static def buildTime() { + return new Date().format("yyyyMMdd"); +} + +android { + signingConfigs { + release { + keyAlias keystoreProperties['keyAlias'] + keyPassword keystoreProperties['keyPassword'] + storeFile file(keystoreProperties['storeFile']) + storePassword keystoreProperties['storePassword'] + } + } + + compileSdkVersion build_versions.target_sdk + defaultConfig { + applicationId "com.guiying.module" + minSdkVersion build_versions.min_sdk + targetSdkVersion build_versions.target_sdk + versionCode 1 + versionName "1.0" + multiDexEnabled true + //打包时间 + resValue "string", "build_time", buildTime() + } + + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + buildTypes { + release { + //更改AndroidManifest.xml中预先定义好占位符信息 + //manifestPlaceholders = [app_icon: "@drawable/icon"] + // 不显示Log + buildConfigField "boolean", "LEO_DEBUG", "false" + //是否zip对齐 + zipAlignEnabled true + // 缩减resource文件 + shrinkResources true + //Proguard + minifyEnabled true + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + //签名 + signingConfig signingConfigs.release + } + + debug { + //给applicationId添加后缀“.debug” + applicationIdSuffix ".debug" + //manifestPlaceholders = [app_icon: "@drawable/launch_beta"] + buildConfigField "boolean", "LOG_DEBUG", "true" + zipAlignEnabled false + shrinkResources false + minifyEnabled false + debuggable true + } + } + + +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation deps.support.multidex + implementation project(':lib_common') + if (!isModule.toBoolean()) { + implementation project(':module_main') + implementation project(':module_girls') + implementation project(':module_news') + } +} diff --git a/module_app/libs/acra-4.5.0.jar b/module_app/libs/acra-4.5.0.jar new file mode 100644 index 0000000..f5100d6 Binary files /dev/null and b/module_app/libs/acra-4.5.0.jar differ diff --git a/module_app/proguard-rules.pro b/module_app/proguard-rules.pro new file mode 100644 index 0000000..7715cfe --- /dev/null +++ b/module_app/proguard-rules.pro @@ -0,0 +1,335 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in D:\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 *; +#} +#---------------------------------基本指令区---------------------------------- +-ignorewarnings +-dontusemixedcaseclassnames # 是否使用大小写混合 +-dontpreverify # 混淆时是否做预校验 +-verbose # 混淆时是否记录日志 +-printmapping proguardMapping.txt +-optimizationpasses 5 # 指定代码的压缩级别 +-dontskipnonpubliclibraryclassmembers + + +-optimizations !code/simplification/arithmetic,!field/*,!class/merging/* +-keepattributes *Annotation*,InnerClasses +-keepattributes Signature # 避免混淆泛型 +-keepattributes EnclosingMethod +-keepattributes SourceFile,LineNumberTable #运行抛出异常时保留代码行号 +-keepattributes Exceptions # 解决AGPBI警告 + +#继承自activity,application,service,broadcastReceiver,contentprovider....不进行混淆 +-keep public class * extends android.app.Activity +-keep public class * extends android.app.Application +-keep public class * extends android.support.multidex.MultiDexApplication +-keep public class * extends android.app.Service +-keep public class * extends android.content.BroadcastReceiver +-keep public class * extends android.content.ContentProvider +-keep public class * extends android.app.backup.BackupAgentHelper +-keep public class * extends android.preference.Preference +-keep public class * extends android.view.View +-keep public class com.android.vending.licensing.ILicensingService +-keep class android.support.** {*;} + +# 所有View的子类及其子类的get、set方法都不进行混淆 +-keep public class * extends android.view.View{ + *** get*(); + void set*(***); + public (android.content.Context); + public (android.content.Context, android.util.AttributeSet); + public (android.content.Context, android.util.AttributeSet, int); +} + +# 这个主要是在layout 中写的onclick方法android:onclick="onClick",不进行混淆 +-keepclassmembers class * extends android.app.Activity { + public void *(android.view.View); +} + + +# 对于带有回调函数onXXEvent的,不能被混淆 +-keepclassmembers class * { + void *(*Event); +} + +# 枚举类不能被混淆 +-keepclassmembers enum * { + public static **[] values(); + public static ** valueOf(java.lang.String); +} + +# natvie 方法不混淆 +-keepclasseswithmembernames class * { + native ; +} + +# 保持 Parcelable 不被混淆 +-keep class * implements android.os.Parcelable { + public static final android.os.Parcelable$Creator *; +} + + +#不混淆Serializable接口的子类中指定的某些成员变量和方法 +-keepclassmembers class * implements java.io.Serializable { + static final long serialVersionUID; + private static final java.io.ObjectStreamField[] serialPersistentFields; + !static !transient ; + private void writeObject(java.io.ObjectOutputStream); + private void readObject(java.io.ObjectInputStream); + java.lang.Object writeReplace(); + java.lang.Object readResolve(); +} + + +-keepclassmembers class * { + public (org.json.JSONObject); +} + + +# 不混淆R类里及其所有内部static类中的所有static变量字段,$是用来分割内嵌类与其母体的标志 +-keep public class **.R$*{ + public static final int *; +} + + +#(可选)避免Log打印输出 +-assumenosideeffects class android.util.Log { + public static *** v(...); + public static *** d(...); + public static *** i(...); + public static *** w(...); + } + +#---------------------------------webview------------------------------------ +-keepclassmembers class fqcn.of.javascript.interface.for.webview { + public *; +} +-keepclassmembers class * extends android.webkit.webViewClient { + public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap); + public boolean *(android.webkit.WebView, java.lang.String); +} + +#---------------------------------业务组件实体类--------------------------------- + +-keep class com.guiying.news.data.bean.** {*;} +-keep class com.guiying.girls.data.bean.** {*;} + +#---------------------------------第三方库及jar包------------------------------- + +#litepal数据库不能被混淆 +-keep class org.litepal.** {*;} +-keep class * extends org.litepal.crud.DataSupport {*;} + +#Glide不能被混淆 +-keep public class * implements com.bumptech.glide.module.GlideModule +-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** { + **[] $VALUES; + public *; +} + + +#PersistentCookieJar +-dontwarn com.franmontiel.persistentcookiejar.** +-keep class com.franmontiel.persistentcookiejar.** + + +#activityrouter +-keep class com.github.mzule.activityrouter.router.** { *; } + +#友盟统计 +-keep class com.umeng.analytics.** {*;} +-dontwarn com.umeng.analytics.** +#友盟推送 +-dontwarn com.taobao.** +-dontwarn anet.channel.** +-dontwarn anetwork.channel.** +-dontwarn org.android.** +-dontwarn org.apache.thrift.** +-dontwarn com.xiaomi.** +-dontwarn com.huawei.** +-keep class com.taobao.** {*;} +-keep class org.android.** {*;} +-keep class anet.channel.** {*;} +-keep class com.umeng.** {*;} +-keep class com.xiaomi.** {*;} +-keep class com.huawei.** {*;} +-keep class org.apache.thrift.** {*;} +-keep class com.alibaba.sdk.android.**{*;} +-keep class com.ut.**{*;} +-keep class com.ta.**{*;} + + +#换肤框架的混淆文件 +-keep class solid.ren.skinlibrary.** {*;} +-dontwarn solid.ren.skinlibrary.** + + +#高德相关混淆文件 +#3D 地图 +-keep class com.amap.api.** {*;} +-keep class com.autonavi.** {*;} +-keep class com.a.a.** {*;} +-keep class com.loc.** {*;} +-dontwarn com.amap.api.** +-dontwarn com.autonavi.** +-dontwarn com.a.a.** +-dontwarn com.loc.** + + +# simple-xml-core的SDK +-keep class org.simpleframework.xml.** {*;} +-dontwarn org.simpleframework.xml.** + +# acra的 SDK +-keep class org.acra.** {*;} +-dontwarn org.acra.** + +# 网络请求库async-http +-keep class com.loopj.android.http.** {*;} +-dontwarn com.loopj.android.http.** + + +#pinyin4j +-dontwarn net.soureceforge.pinyin4j.** +-dontwarn demo.** +-keep class net.sourceforge.pinyin4j.** { *;} +-keep class demo.** { *;} +-keep class com.hp.** { *;} + +#httpclient (org.apache.http.legacy.jar) +-dontwarn android.net.compatibility.** +-dontwarn android.net.http.** +-dontwarn com.android.internal.http.multipart.** +-dontwarn org.apache.commons.** +-dontwarn org.apache.http.** +-dontwarn org.apache.http.protocol.** +-keep class android.net.compatibility.**{*;} +-keep class android.net.http.**{*;} +-keep class com.android.internal.http.multipart.**{*;} +-keep class org.apache.commons.**{*;} +-keep class org.apache.org.**{*;} +-keep class org.apache.harmony.**{*;} + +#图表库 +-keep class com.github.mikephil.charting.** {*;} +-dontwarn com.github.mikephil.charting.** + +# 讯飞语音 +-keep class com.chinaMobile.** {*;} +-keep class com.iflytek.** {*;} +-keep class com.iflytek.sunflower.** {*;} +-dontwarn com.iflytek.sunflower.** +-dontwarn com.chinaMobile.** +-dontwarn com.iflytek.** + +# greenDao混淆 +-keep class de.greenrobot.dao.** {*;} +-keepclassmembers class * extends de.greenrobot.dao.AbstractDao { + public static Java.lang.String TABLENAME; +} +-keep class **$Properties + +# gson +-keep class com.google.gson.** {*;} +-keep class com.google.**{*;} +-keep class sun.misc.Unsafe { *; } +-keep class com.google.gson.stream.** { *; } +-keep class com.google.gson.examples.android.model.** { *; } + +# zxing +-keep class com.google.zxing.** {*;} +-dontwarn com.google.zxing.** + +##百度定位 +-keep class com.baidu.** {*;} +-keep class vi.com.** {*;} +-dontwarn com.baidu.** + +## okhttp +-dontwarn com.squareup.okhttp.** +-keep class com.squareup.okhttp.{*;} + +#okhttp3.x +-dontwarn com.squareup.okhttp3.** +-keep class com.squareup.okhttp3.** { *;} +-dontwarn okio.** + +#retrofit +-dontwarn retrofit.** +-keep class retrofit.** { *; } +-dontwarn okio.** + + +#recyclerview-animators +-keep class jp.wasabeef.** {*;} +-dontwarn jp.wasabeef.* + +#multistateview +-keep class com.kennyc.view.** { *; } +-dontwarn com.kennyc.view.* + +# universal-image-loader 混淆 +-dontwarn com.nostra13.universalimageloader.** +-keep class com.nostra13.universalimageloader.** { *; } + + +#-ButterKnife 7.0 + -keep class butterknife.** { *; } + -dontwarn butterknife.internal.** + -keep class **$$ViewBinder { *; } + -keepclasseswithmembernames class * { + @butterknife.* ; + } + -keepclasseswithmembernames class * { + @butterknife.* ; + } + +#eventbus 3.0 +-keepattributes *Annotation* +-keepclassmembers class ** { + @org.greenrobot.eventbus.Subscribe ; +} +-keep enum org.greenrobot.eventbus.ThreadMode { *; } +-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent { + (java.lang.Throwable); +} + +#EventBus +-keepclassmembers class ** { + public void onEvent*(**); +} +-keepclassmembers class ** { +public void xxxxxx(**); +} + +# support-v4 +-dontwarn android.support.v4.** +-keep class android.support.v4.app.** { *; } +-keep interface android.support.v4.app.** { *; } +-keep class android.support.v4.** { *; } + + +# support-v7 +-dontwarn android.support.v7.** +-keep class android.support.v7.internal.** { *; } +-keep interface android.support.v7.internal.** { *; } +-keep class android.support.v7.** { *; } + +# support design +-dontwarn android.support.design.** +-keep class android.support.design.** { *; } +-keep interface android.support.design.** { *; } +-keep public class android.support.design.R$* { *; } diff --git a/module_app/src/main/AndroidManifest.xml b/module_app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..315d6cb --- /dev/null +++ b/module_app/src/main/AndroidManifest.xml @@ -0,0 +1,20 @@ + + + + + + + + + + \ No newline at end of file diff --git a/module_app/src/main/java/com/guiying/module/MyApplication.java b/module_app/src/main/java/com/guiying/module/MyApplication.java new file mode 100644 index 0000000..72e9506 --- /dev/null +++ b/module_app/src/main/java/com/guiying/module/MyApplication.java @@ -0,0 +1,84 @@ +package com.guiying.module; + +import android.content.Context; +import android.support.multidex.MultiDex; + +import com.alibaba.android.arouter.launcher.ARouter; +import com.guiying.module.common.base.BaseApplication; +import com.guiying.module.common.utils.Utils; + +import org.acra.ACRA; +import org.acra.ReportField; +import org.acra.ReportingInteractionMode; +import org.acra.annotation.ReportsCrashes; +import org.acra.collector.CrashReportData; +import org.acra.sender.EmailIntentSender; +import org.acra.sender.ReportSender; +import org.acra.sender.ReportSenderException; + +/** + *

这里仅需做一些初始化的工作

+ * + * @author 张华洋 2017/2/15 20:14 + * @version V1.2.0 + * @name MyApplication + */ +@ReportsCrashes( + mailTo = "guiying705@Gmail.com", + mode = ReportingInteractionMode.DIALOG, + customReportContent = { + ReportField.APP_VERSION_NAME, + ReportField.ANDROID_VERSION, + ReportField.PHONE_MODEL, + ReportField.CUSTOM_DATA, + ReportField.BRAND, + ReportField.STACK_TRACE, + ReportField.LOGCAT, + ReportField.USER_COMMENT}, + resToastText = R.string.crash_toast_text, + resDialogText = R.string.crash_dialog_text, + resDialogTitle = R.string.crash_dialog_title) +public class MyApplication extends BaseApplication { + + + @Override + public void onCreate() { + super.onCreate(); + if (Utils.isAppDebug()) { + //开启InstantRun之后,一定要在ARouter.init之前调用openDebug + ARouter.openDebug(); + ARouter.openLog(); + } + ARouter.init(this); + //崩溃日志记录初始化 + ACRA.init(this); + ACRA.getErrorReporter().removeAllReportSenders(); + ACRA.getErrorReporter().setReportSender(new CrashReportSender()); + } + + + @Override + protected void attachBaseContext(Context base) { + super.attachBaseContext(base); + // dex突破65535的限制 + MultiDex.install(this); + } + + + /** + * 发送崩溃日志 + */ + private class CrashReportSender implements ReportSender { + CrashReportSender() { + ACRA.getErrorReporter().putCustomData("PLATFORM", "ANDROID"); + ACRA.getErrorReporter().putCustomData("BUILD_ID", android.os.Build.ID); + ACRA.getErrorReporter().putCustomData("DEVICE_NAME", android.os.Build.PRODUCT); + } + + @Override + public void send(Context context, CrashReportData crashReportData) throws ReportSenderException { + EmailIntentSender emailSender = new EmailIntentSender(getApplicationContext()); + emailSender.send(context, crashReportData); + } + } +} diff --git a/module_app/src/main/res/values/strings.xml b/module_app/src/main/res/values/strings.xml new file mode 100644 index 0000000..9b547db --- /dev/null +++ b/module_app/src/main/res/values/strings.xml @@ -0,0 +1,12 @@ + + 组件化项目 + + module + + + 程序崩溃了 + 感谢您对我们的支持! + 发送崩溃日志 + 发送成功 + + diff --git a/girls/.gitignore b/module_girls/.gitignore similarity index 100% rename from girls/.gitignore rename to module_girls/.gitignore diff --git a/module_girls/build.gradle b/module_girls/build.gradle new file mode 100644 index 0000000..a1838bd --- /dev/null +++ b/module_girls/build.gradle @@ -0,0 +1,53 @@ +if (isModule.toBoolean()) { + apply plugin: 'com.android.application' +} else { + apply plugin: 'com.android.library' +} + +android { + compileSdkVersion build_versions.target_sdk + defaultConfig { + minSdkVersion build_versions.min_sdk + targetSdkVersion build_versions.target_sdk + versionCode 1 + versionName "1.0" + + javaCompileOptions { + annotationProcessorOptions { + arguments = [ moduleName : project.getName() ] + } + } + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + sourceSets { + main { + if (isModule.toBoolean()) { + manifest.srcFile 'src/main/module/AndroidManifest.xml' + } else { + manifest.srcFile 'src/main/AndroidManifest.xml' + //集成开发模式下排除debug文件夹中的所有Java文件 + java { + exclude 'debug/**' + } + } + } + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + annotationProcessor deps.arouter_compiler + implementation project(':lib_common') +} diff --git a/girls/src/main/release/AndroidManifest.xml b/module_girls/src/main/AndroidManifest.xml similarity index 55% rename from girls/src/main/release/AndroidManifest.xml rename to module_girls/src/main/AndroidManifest.xml index facd819..48584ac 100644 --- a/girls/src/main/release/AndroidManifest.xml +++ b/module_girls/src/main/AndroidManifest.xml @@ -1,10 +1,14 @@ + package="com.guiying.module.girls"> + diff --git a/girls/src/main/java/com/guiying/girls/Constants.java b/module_girls/src/main/java/com/guiying/module/girls/Constants.java similarity index 64% rename from girls/src/main/java/com/guiying/girls/Constants.java rename to module_girls/src/main/java/com/guiying/module/girls/Constants.java index ad755b3..419b643 100644 --- a/girls/src/main/java/com/guiying/girls/Constants.java +++ b/module_girls/src/main/java/com/guiying/module/girls/Constants.java @@ -1,4 +1,4 @@ -package com.guiying.girls; +package com.guiying.module.girls; /** * 保存项目中用到的常量 @@ -10,4 +10,7 @@ public interface Constants { */ String GAN_HUO_API = "http://gank.io/api/data/"; + String INTENT_GIRLS = "girls"; + String INTENT_INDEX = "index"; + } diff --git a/module_girls/src/main/java/com/guiying/module/girls/GirlsFragment.java b/module_girls/src/main/java/com/guiying/module/girls/GirlsFragment.java new file mode 100644 index 0000000..43accad --- /dev/null +++ b/module_girls/src/main/java/com/guiying/module/girls/GirlsFragment.java @@ -0,0 +1,42 @@ +package com.guiying.module.girls; + + +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.guiying.module.common.base.BaseFragment; + + +/** + * A simple {@link Fragment} subclass. + */ +public class GirlsFragment extends BaseFragment { + + /** + * Use this factory method to create a new instance of + * this fragment using the provided parameters. + * + * @return A new instance of fragment GirlsFragment. + */ + public static GirlsFragment newInstance() { + return new GirlsFragment(); + } + + + public GirlsFragment() { + // Required empty public constructor + } + + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + return inflater.inflate(R.layout.fragment_girls, container, false); + } + + +} diff --git a/module_girls/src/main/java/com/guiying/module/girls/MyDelegate.java b/module_girls/src/main/java/com/guiying/module/girls/MyDelegate.java new file mode 100644 index 0000000..dc0ecf4 --- /dev/null +++ b/module_girls/src/main/java/com/guiying/module/girls/MyDelegate.java @@ -0,0 +1,38 @@ +package com.guiying.module.girls; + +import android.support.annotation.Keep; + +import com.guiying.module.common.base.IApplicationDelegate; +import com.guiying.module.common.base.ViewManager; + +/** + *

类说明

+ * + * @author 张华洋 2017/9/20 22:29 + * @version V2.8.3 + * @name MyDelegate + */ +@Keep +public class MyDelegate implements IApplicationDelegate { + + @Override + public void onCreate() { + //主动添加 + ViewManager.getInstance().addFragment(0, GirlsFragment.newInstance()); + } + + @Override + public void onTerminate() { + + } + + @Override + public void onLowMemory() { + + } + + @Override + public void onTrimMemory(int level) { + + } +} diff --git a/module_girls/src/main/java/com/guiying/module/girls/MyViewDelegate.java b/module_girls/src/main/java/com/guiying/module/girls/MyViewDelegate.java new file mode 100644 index 0000000..3d4294e --- /dev/null +++ b/module_girls/src/main/java/com/guiying/module/girls/MyViewDelegate.java @@ -0,0 +1,28 @@ +package com.guiying.module.girls; + +import android.support.annotation.Keep; +import android.view.View; + +import com.guiying.module.common.base.BaseFragment; +import com.guiying.module.common.base.IViewDelegate; + +/** + *

类说明

+ * + * @author 张华洋 2018/1/4 22:16 + * @version V2.8.3 + * @name MyViewDelegate + */ +@Keep +public class MyViewDelegate implements IViewDelegate { + + @Override + public BaseFragment getFragment(String name) { + return GirlsFragment.newInstance(); + } + + @Override + public View getView(String name) { + return null; + } +} diff --git a/girls/src/main/java/com/guiying/girls/data/GirlsDataSource.java b/module_girls/src/main/java/com/guiying/module/girls/data/GirlsDataSource.java similarity index 71% rename from girls/src/main/java/com/guiying/girls/data/GirlsDataSource.java rename to module_girls/src/main/java/com/guiying/module/girls/data/GirlsDataSource.java index c05d2bb..3f2755d 100644 --- a/girls/src/main/java/com/guiying/girls/data/GirlsDataSource.java +++ b/module_girls/src/main/java/com/guiying/module/girls/data/GirlsDataSource.java @@ -1,6 +1,6 @@ -package com.guiying.girls.data; +package com.guiying.module.girls.data; -import com.guiying.girls.data.parser.GirlsParser; +import com.guiying.module.girls.data.bean.GirlsParser; public interface GirlsDataSource { diff --git a/girls/src/main/java/com/guiying/girls/data/bean/Girls.java b/module_girls/src/main/java/com/guiying/module/girls/data/bean/Girls.java similarity index 98% rename from girls/src/main/java/com/guiying/girls/data/bean/Girls.java rename to module_girls/src/main/java/com/guiying/module/girls/data/bean/Girls.java index 162b6b5..26573c9 100644 --- a/girls/src/main/java/com/guiying/girls/data/bean/Girls.java +++ b/module_girls/src/main/java/com/guiying/module/girls/data/bean/Girls.java @@ -1,4 +1,4 @@ -package com.guiying.girls.data.bean; +package com.guiying.module.girls.data.bean; import android.os.Parcel; import android.os.Parcelable; diff --git a/girls/src/main/java/com/guiying/girls/data/parser/GirlsParser.java b/module_girls/src/main/java/com/guiying/module/girls/data/bean/GirlsParser.java similarity index 94% rename from girls/src/main/java/com/guiying/girls/data/parser/GirlsParser.java rename to module_girls/src/main/java/com/guiying/module/girls/data/bean/GirlsParser.java index 0937ef4..d9c4d34 100644 --- a/girls/src/main/java/com/guiying/girls/data/parser/GirlsParser.java +++ b/module_girls/src/main/java/com/guiying/module/girls/data/bean/GirlsParser.java @@ -1,6 +1,4 @@ -package com.guiying.girls.data.parser; - -import com.guiying.girls.data.bean.Girls; +package com.guiying.module.girls.data.bean; import java.util.List; diff --git a/girls/src/main/java/com/guiying/girls/data/source/RemoteGirlsDataSource.java b/module_girls/src/main/java/com/guiying/module/girls/data/source/RemoteGirlsDataSource.java similarity index 66% rename from girls/src/main/java/com/guiying/girls/data/source/RemoteGirlsDataSource.java rename to module_girls/src/main/java/com/guiying/module/girls/data/source/RemoteGirlsDataSource.java index 0756f37..457f412 100644 --- a/girls/src/main/java/com/guiying/girls/data/source/RemoteGirlsDataSource.java +++ b/module_girls/src/main/java/com/guiying/module/girls/data/source/RemoteGirlsDataSource.java @@ -1,13 +1,13 @@ -package com.guiying.girls.data.source; +package com.guiying.module.girls.data.source; -import com.guiying.common.http.HttpClient; -import com.guiying.common.http.OnResultListener; -import com.guiying.girls.Constants; -import com.guiying.girls.data.GirlsDataSource; -import com.guiying.girls.data.parser.GirlsParser; +import com.guiying.module.common.http.DataType; +import com.guiying.module.common.http.HttpClient; +import com.guiying.module.common.http.OnResultListener; +import com.guiying.module.girls.Constants; +import com.guiying.module.girls.data.GirlsDataSource; +import com.guiying.module.girls.data.bean.GirlsParser; -import static com.guiying.common.http.HttpClient.OBJECT; public class RemoteGirlsDataSource implements GirlsDataSource { @@ -17,7 +17,7 @@ public void getGirls(int size, int page, final LoadGirlsCallback callback) { HttpClient client = new HttpClient.Builder() .baseUrl(Constants.GAN_HUO_API) .url("福利/" + size + "/" + page) - .bodyType(OBJECT, GirlsParser.class) + .bodyType(DataType.JSON_OBJECT, GirlsParser.class) .build(); client.get(new OnResultListener() { diff --git a/module_girls/src/main/java/com/guiying/module/girls/girl/GirlActivity.java b/module_girls/src/main/java/com/guiying/module/girls/girl/GirlActivity.java new file mode 100644 index 0000000..bd1dd78 --- /dev/null +++ b/module_girls/src/main/java/com/guiying/module/girls/girl/GirlActivity.java @@ -0,0 +1,57 @@ +package com.guiying.module.girls.girl; + +import android.os.Bundle; +import android.support.v4.view.ViewPager; +import android.view.WindowManager; + +import com.alibaba.android.arouter.facade.annotation.Route; +import com.guiying.module.common.base.BaseActivity; +import com.guiying.module.common.widget.HackyViewPager; +import com.guiying.module.girls.Constants; +import com.guiying.module.girls.data.bean.Girls; + +import java.util.List; + +/** + *

+ * + * @author 张华洋 2017/5/19 20:24 + * @version V1.1 + * @name GirlActivity + */ +@Route(path = "/girls/detail") +public class GirlActivity extends BaseActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); + getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN); + if (getIntent() != null) { + List mData = getIntent().getParcelableArrayListExtra(Constants.INTENT_GIRLS); + int mCurrentIndex = getIntent().getIntExtra(Constants.INTENT_INDEX, 0); + HackyViewPager viewPager = new HackyViewPager(this); + setContentView(viewPager); + GirlAdapter adapter = new GirlAdapter(this, mData); + viewPager.setAdapter(adapter); + viewPager.setCurrentItem(mCurrentIndex); + viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + + } + + @Override + public void onPageSelected(int position) { + + } + + @Override + public void onPageScrollStateChanged(int state) { + + } + }); + } + } + +} diff --git a/module_girls/src/main/java/com/guiying/module/girls/girl/GirlAdapter.java b/module_girls/src/main/java/com/guiying/module/girls/girl/GirlAdapter.java new file mode 100644 index 0000000..dce7361 --- /dev/null +++ b/module_girls/src/main/java/com/guiying/module/girls/girl/GirlAdapter.java @@ -0,0 +1,76 @@ +package com.guiying.module.girls.girl; + +import android.content.Context; +import android.support.v4.view.PagerAdapter; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.bumptech.glide.Glide; +import com.github.chrisbanes.photoview.PhotoView; +import com.guiying.module.girls.R; +import com.guiying.module.girls.data.bean.Girls; + +import java.util.List; + +/** + *

+ * + * @author 张华洋 2017/5/19 20:31 + * @version V1.1 + * @name GirlAdapter + */ +public class GirlAdapter extends PagerAdapter { + + private Context mContext; + private List mData; + private LayoutInflater layoutInflater; + private View mCurrentView; + + public GirlAdapter(Context context, List data) { + mContext = context; + mData = data; + layoutInflater = LayoutInflater.from(this.mContext); + } + + @Override + public int getCount() { + if (mData == null) { + return 0; + } + return mData.size(); + } + + @Override + public void setPrimaryItem(ViewGroup container, int position, Object object) { + super.setPrimaryItem(container, position, object); + mCurrentView = (View) object; + } + + @Override + public View instantiateItem(ViewGroup container, int position) { + final String imageUrl = mData.get(position).getUrl(); + View view = layoutInflater.inflate(R.layout.item_girl_detail, container, false); + PhotoView imageView = (PhotoView) view.findViewById(R.id.girl_image); + Glide.with(mContext) + .load(imageUrl) + .thumbnail(0.2f) + .into(imageView); + container.addView(view); + return view; + } + + @Override + public void destroyItem(ViewGroup container, int position, Object object) { + container.removeView((View) object); + } + + @Override + public boolean isViewFromObject(View view, Object object) { + return view == object; + } + + public View getPrimaryItem() { + return mCurrentView; + } +} diff --git a/girls/src/main/java/com/guiying/girls/main/GirlsActivity.java b/module_girls/src/main/java/com/guiying/module/girls/main/GirlsActivity.java similarity index 70% rename from girls/src/main/java/com/guiying/girls/main/GirlsActivity.java rename to module_girls/src/main/java/com/guiying/module/girls/main/GirlsActivity.java index b0a0851..9a64571 100644 --- a/girls/src/main/java/com/guiying/girls/main/GirlsActivity.java +++ b/module_girls/src/main/java/com/guiying/module/girls/main/GirlsActivity.java @@ -1,12 +1,12 @@ -package com.guiying.girls.main; +package com.guiying.module.girls.main; import android.os.Bundle; -import com.github.mzule.activityrouter.annotation.Router; -import com.guiying.common.base.BaseActionBarActivity; -import com.guiying.girls.R; +import com.alibaba.android.arouter.facade.annotation.Route; +import com.guiying.module.common.base.BaseActionBarActivity; +import com.guiying.module.girls.R; -@Router("girls") +@Route(path = "/girls/list") public class GirlsActivity extends BaseActionBarActivity { private GirlsView mView; diff --git a/girls/src/main/java/com/guiying/girls/main/GirlsAdapter.java b/module_girls/src/main/java/com/guiying/module/girls/main/GirlsAdapter.java similarity index 93% rename from girls/src/main/java/com/guiying/girls/main/GirlsAdapter.java rename to module_girls/src/main/java/com/guiying/module/girls/main/GirlsAdapter.java index eefbad0..6ee991a 100644 --- a/girls/src/main/java/com/guiying/girls/main/GirlsAdapter.java +++ b/module_girls/src/main/java/com/guiying/module/girls/main/GirlsAdapter.java @@ -1,4 +1,4 @@ -package com.guiying.girls.main; +package com.guiying.module.girls.main; import android.content.Context; import android.view.View; @@ -7,8 +7,8 @@ import com.bumptech.glide.Glide; import com.bumptech.glide.load.engine.DiskCacheStrategy; -import com.guiying.girls.R; -import com.guiying.girls.data.bean.Girls; +import com.guiying.module.girls.R; +import com.guiying.module.girls.data.bean.Girls; import com.jude.easyrecyclerview.adapter.BaseViewHolder; import com.jude.easyrecyclerview.adapter.RecyclerArrayAdapter; diff --git a/girls/src/main/java/com/guiying/girls/main/GirlsContract.java b/module_girls/src/main/java/com/guiying/module/girls/main/GirlsContract.java similarity index 76% rename from girls/src/main/java/com/guiying/girls/main/GirlsContract.java rename to module_girls/src/main/java/com/guiying/module/girls/main/GirlsContract.java index d4cd0d5..fd57180 100644 --- a/girls/src/main/java/com/guiying/girls/main/GirlsContract.java +++ b/module_girls/src/main/java/com/guiying/module/girls/main/GirlsContract.java @@ -1,8 +1,8 @@ -package com.guiying.girls.main; +package com.guiying.module.girls.main; -import com.guiying.common.base.BasePresenter; -import com.guiying.common.base.BaseView; -import com.guiying.girls.data.bean.Girls; +import com.guiying.module.common.base.BasePresenter; +import com.guiying.module.common.base.BaseView; +import com.guiying.module.girls.data.bean.Girls; import java.util.List; diff --git a/girls/src/main/java/com/guiying/girls/main/GirlsPresenter.java b/module_girls/src/main/java/com/guiying/module/girls/main/GirlsPresenter.java similarity index 82% rename from girls/src/main/java/com/guiying/girls/main/GirlsPresenter.java rename to module_girls/src/main/java/com/guiying/module/girls/main/GirlsPresenter.java index 5a75d89..a94fa8b 100644 --- a/girls/src/main/java/com/guiying/girls/main/GirlsPresenter.java +++ b/module_girls/src/main/java/com/guiying/module/girls/main/GirlsPresenter.java @@ -1,8 +1,8 @@ -package com.guiying.girls.main; +package com.guiying.module.girls.main; -import com.guiying.girls.data.GirlsDataSource; -import com.guiying.girls.data.parser.GirlsParser; -import com.guiying.girls.data.source.RemoteGirlsDataSource; +import com.guiying.module.girls.data.GirlsDataSource; +import com.guiying.module.girls.data.bean.GirlsParser; +import com.guiying.module.girls.data.source.RemoteGirlsDataSource; /** *

类说明

@@ -46,6 +46,6 @@ public void onDataNotAvailable() { @Override public void start() { - getGirls(10, 1, true); + getGirls(20, 1, true); } } diff --git a/girls/src/main/java/com/guiying/girls/main/GirlsView.java b/module_girls/src/main/java/com/guiying/module/girls/main/GirlsView.java similarity index 75% rename from girls/src/main/java/com/guiying/girls/main/GirlsView.java rename to module_girls/src/main/java/com/guiying/module/girls/main/GirlsView.java index 569b9a7..dc83d90 100644 --- a/girls/src/main/java/com/guiying/girls/main/GirlsView.java +++ b/module_girls/src/main/java/com/guiying/module/girls/main/GirlsView.java @@ -1,6 +1,9 @@ -package com.guiying.girls.main; +package com.guiying.module.girls.main; import android.content.Context; +import android.content.Intent; +import android.support.v4.app.ActivityOptionsCompat; +import android.support.v4.content.ContextCompat; import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.widget.StaggeredGridLayoutManager; import android.util.AttributeSet; @@ -8,8 +11,11 @@ import android.view.ViewStub; import android.widget.FrameLayout; -import com.guiying.girls.R; -import com.guiying.girls.data.bean.Girls; +import com.guiying.module.common.utils.Utils; +import com.guiying.module.girls.Constants; +import com.guiying.module.girls.R; +import com.guiying.module.girls.data.bean.Girls; +import com.guiying.module.girls.girl.GirlActivity; import com.jude.easyrecyclerview.EasyRecyclerView; import com.jude.easyrecyclerview.adapter.BaseViewHolder; import com.jude.easyrecyclerview.adapter.RecyclerArrayAdapter; @@ -35,7 +41,7 @@ public class GirlsView extends FrameLayout implements GirlsContract.View, SwipeR private GirlsAdapter mAdapter; private ArrayList mData; private int page = 1; - private int size = 10; + private int size = 20; public GirlsView(Context context) { super(context); @@ -52,26 +58,33 @@ private void initView() { inflate(getContext(), R.layout.view_girls_content, this); mNetworkErrorLayout = (ViewStub) findViewById(R.id.network_error_layout); mGirlsRecyclerView = (EasyRecyclerView) findViewById(R.id.girls_recycler_view); - - mData = new ArrayList<>(); StaggeredGridLayoutManager staggeredGridLayoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL); mGirlsRecyclerView.setLayoutManager(staggeredGridLayoutManager); mAdapter = new GirlsAdapter(getContext()); mGirlsRecyclerView.setAdapterWithProgress(mAdapter); - + mGirlsRecyclerView.setRefreshingColor( + ContextCompat.getColor(getContext(), R.color.colorPrimary), + ContextCompat.getColor(getContext(), android.R.color.holo_blue_light), + ContextCompat.getColor(getContext(), android.R.color.holo_green_light) + ); mAdapter.setMore(R.layout.layout_load_more, this); mAdapter.setNoMore(R.layout.layout_load_no_more); mAdapter.setError(R.layout.layout_load_error); mAdapter.setOnMyItemClickListener(new GirlsAdapter.OnMyItemClickListener() { @Override public void onItemClick(int position, BaseViewHolder holder) { - + Intent intent = new Intent(Utils.getActivity(GirlsView.this), GirlActivity.class); + intent.putParcelableArrayListExtra(Constants.INTENT_GIRLS, mData); + intent.putExtra(Constants.INTENT_INDEX, position); + ActivityOptionsCompat options = ActivityOptionsCompat.makeScaleUpAnimation(holder.itemView, holder.itemView.getWidth() / 2, holder.itemView.getHeight() / 2, 0, 0); + Utils.getActivity(GirlsView.this).startActivity(intent, options.toBundle()); } }); mGirlsRecyclerView.setRefreshListener(this); + mData = new ArrayList<>(); mActive = true; } diff --git a/girls/src/main/java/debug/GirlsApplication.java b/module_girls/src/main/java/debug/GirlsApplication.java similarity index 87% rename from girls/src/main/java/debug/GirlsApplication.java rename to module_girls/src/main/java/debug/GirlsApplication.java index b93eb55..052a4e6 100644 --- a/girls/src/main/java/debug/GirlsApplication.java +++ b/module_girls/src/main/java/debug/GirlsApplication.java @@ -1,8 +1,8 @@ package debug; -import com.guiying.common.base.BaseApplication; -import com.guiying.common.http.HttpClient; -import com.guiying.common.http.OnResultListener; +import com.guiying.module.common.base.BaseApplication; +import com.guiying.module.common.http.HttpClient; +import com.guiying.module.common.http.OnResultListener; import com.orhanobut.logger.Logger; /** diff --git a/girls/src/main/debug/AndroidManifest.xml b/module_girls/src/main/module/AndroidManifest.xml similarity index 77% rename from girls/src/main/debug/AndroidManifest.xml rename to module_girls/src/main/module/AndroidManifest.xml index 3c5bc0c..f283bb9 100644 --- a/girls/src/main/debug/AndroidManifest.xml +++ b/module_girls/src/main/module/AndroidManifest.xml @@ -1,6 +1,6 @@ + package="com.guiying.module.girls">
+ \ No newline at end of file diff --git a/girls/src/main/res/layout/activity_girls.xml b/module_girls/src/main/res/layout/activity_girls.xml similarity index 88% rename from girls/src/main/res/layout/activity_girls.xml rename to module_girls/src/main/res/layout/activity_girls.xml index 07e6aed..5109cf6 100644 --- a/girls/src/main/res/layout/activity_girls.xml +++ b/module_girls/src/main/res/layout/activity_girls.xml @@ -4,7 +4,7 @@ android:id="@+id/activity_girls" android:layout_width="match_parent" android:layout_height="match_parent" - tools:context="com.guiying.girls.main.GirlsActivity"> + tools:context=".girls.main.GirlsActivity"> + + + + + diff --git a/girls/src/main/res/layout/item_girl.xml b/module_girls/src/main/res/layout/item_girl.xml similarity index 100% rename from girls/src/main/res/layout/item_girl.xml rename to module_girls/src/main/res/layout/item_girl.xml diff --git a/module_girls/src/main/res/layout/item_girl_detail.xml b/module_girls/src/main/res/layout/item_girl_detail.xml new file mode 100644 index 0000000..5634024 --- /dev/null +++ b/module_girls/src/main/res/layout/item_girl_detail.xml @@ -0,0 +1,14 @@ + + + + + + \ No newline at end of file diff --git a/girls/src/main/res/layout/view_girls_content.xml b/module_girls/src/main/res/layout/view_girls_content.xml similarity index 100% rename from girls/src/main/res/layout/view_girls_content.xml rename to module_girls/src/main/res/layout/view_girls_content.xml diff --git a/girls/src/main/res/values/colors.xml b/module_girls/src/main/res/values/colors.xml similarity index 100% rename from girls/src/main/res/values/colors.xml rename to module_girls/src/main/res/values/colors.xml diff --git a/girls/src/main/res/values/dimens.xml b/module_girls/src/main/res/values/dimens.xml similarity index 100% rename from girls/src/main/res/values/dimens.xml rename to module_girls/src/main/res/values/dimens.xml diff --git a/girls/src/main/res/values/strings.xml b/module_girls/src/main/res/values/strings.xml similarity index 61% rename from girls/src/main/res/values/strings.xml rename to module_girls/src/main/res/values/strings.xml index 567ccc0..2b25680 100644 --- a/girls/src/main/res/values/strings.xml +++ b/module_girls/src/main/res/values/strings.xml @@ -1,5 +1,5 @@ - Girls + Girls组件 Girls diff --git a/main/.gitignore b/module_main/.gitignore similarity index 100% rename from main/.gitignore rename to module_main/.gitignore diff --git a/module_main/build.gradle b/module_main/build.gradle new file mode 100644 index 0000000..a1838bd --- /dev/null +++ b/module_main/build.gradle @@ -0,0 +1,53 @@ +if (isModule.toBoolean()) { + apply plugin: 'com.android.application' +} else { + apply plugin: 'com.android.library' +} + +android { + compileSdkVersion build_versions.target_sdk + defaultConfig { + minSdkVersion build_versions.min_sdk + targetSdkVersion build_versions.target_sdk + versionCode 1 + versionName "1.0" + + javaCompileOptions { + annotationProcessorOptions { + arguments = [ moduleName : project.getName() ] + } + } + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + sourceSets { + main { + if (isModule.toBoolean()) { + manifest.srcFile 'src/main/module/AndroidManifest.xml' + } else { + manifest.srcFile 'src/main/AndroidManifest.xml' + //集成开发模式下排除debug文件夹中的所有Java文件 + java { + exclude 'debug/**' + } + } + } + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + annotationProcessor deps.arouter_compiler + implementation project(':lib_common') +} diff --git a/main/src/main/release/AndroidManifest.xml b/module_main/src/main/AndroidManifest.xml similarity index 53% rename from main/src/main/release/AndroidManifest.xml rename to module_main/src/main/AndroidManifest.xml index 4249b68..db12695 100644 --- a/main/src/main/release/AndroidManifest.xml +++ b/module_main/src/main/AndroidManifest.xml @@ -1,14 +1,20 @@ + + package="com.guiying.module.main"> - + + + + - + \ No newline at end of file diff --git a/module_main/src/main/java/com/guiying/module/main/BottomNavigationActivity.java b/module_main/src/main/java/com/guiying/module/main/BottomNavigationActivity.java new file mode 100644 index 0000000..51c27cf --- /dev/null +++ b/module_main/src/main/java/com/guiying/module/main/BottomNavigationActivity.java @@ -0,0 +1,86 @@ +package com.guiying.module.main; + +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.design.widget.BottomNavigationView; +import android.view.MenuItem; + +import com.guiying.module.common.base.BaseActivity; +import com.guiying.module.common.base.BaseFragment; +import com.guiying.module.common.base.ClassUtils; +import com.guiying.module.common.base.IViewDelegate; +import com.guiying.module.common.base.ViewManager; +import com.guiying.module.common.widget.NoScrollViewPager; + +import java.util.List; + +/** + *

+ * + * @author 张华洋 2017/9/27 10:23 + * @version V1.1 + * @name BottomNavigationActivity + */ +public class BottomNavigationActivity extends BaseActivity { + + private NoScrollViewPager mPager; + private List mFragments; + private FragmentAdapter mAdapter; + + private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener + = new BottomNavigationView.OnNavigationItemSelectedListener() { + + @Override + public boolean onNavigationItemSelected(@NonNull MenuItem item) { + int i = item.getItemId(); + if (i == R.id.navigation_home) { + mPager.setCurrentItem(0); + return true; + } else if (i == R.id.navigation_dashboard) { + mPager.setCurrentItem(1); + return true; + } else if (i == R.id.navigation_notifications) { + mPager.setCurrentItem(2); + return true; + } + return false; + } + + }; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_bottom_navigation); + BottomNavigationView navigation = (BottomNavigationView) findViewById(R.id.navigation); + navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener); + initViewPager(); + } + + private void initViewPager() { + mFragments = ViewManager.getInstance().getAllFragment();//这几个Fragment是主动添加到ViewManager中的 + BaseFragment newsFragment = getNewsFragment();//主动寻找 + mFragments.add(newsFragment); + mPager = (NoScrollViewPager) findViewById(R.id.container_pager); + mAdapter = new FragmentAdapter(getSupportFragmentManager(), mFragments); + mPager.setPagerEnabled(false); + mPager.setAdapter(mAdapter); + } + + + /** + * 在News模块中寻找实现的Fragment + * + * @return Fragment + */ + private BaseFragment getNewsFragment() { + BaseFragment newsFragment = null; + List viewDelegates = ClassUtils.getObjectsWithInterface(this, IViewDelegate.class, "com.guiying.module.news"); + if (viewDelegates != null && !viewDelegates.isEmpty()) { + newsFragment = viewDelegates.get(0).getFragment(""); + } + return newsFragment; + } + +} diff --git a/module_main/src/main/java/com/guiying/module/main/FragmentAdapter.java b/module_main/src/main/java/com/guiying/module/main/FragmentAdapter.java new file mode 100644 index 0000000..dc5b82b --- /dev/null +++ b/module_main/src/main/java/com/guiying/module/main/FragmentAdapter.java @@ -0,0 +1,40 @@ +package com.guiying.module.main; + +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentStatePagerAdapter; + +import com.guiying.module.common.base.BaseFragment; + +import java.util.List; + +/** + *

Fragments适配器

+ * + * @author 张华洋 2017/9/27 10:14 + * @version V1.1 + * @name ResourcePagerAdapter + */ +public class FragmentAdapter extends FragmentStatePagerAdapter { + private List mFragments; + + public FragmentAdapter(FragmentManager fm, List mFragments) { + super(fm); + this.mFragments = mFragments; + } + + @Override + public Fragment getItem(int position) { + return mFragments.get(position); + } + + @Override + public int getCount() { + return mFragments != null ? mFragments.size() : 0; + } + + @Override + public int getItemPosition(Object object) { + return android.support.v4.view.PagerAdapter.POSITION_NONE; + } +} diff --git a/module_main/src/main/java/com/guiying/module/main/MainActivity.java b/module_main/src/main/java/com/guiying/module/main/MainActivity.java new file mode 100644 index 0000000..db0fb8b --- /dev/null +++ b/module_main/src/main/java/com/guiying/module/main/MainActivity.java @@ -0,0 +1,62 @@ +package com.guiying.module.main; + +import android.content.Intent; +import android.os.Bundle; +import android.view.KeyEvent; +import android.view.View; + +import com.alibaba.android.arouter.launcher.ARouter; +import com.guiying.module.common.base.BaseActivity; +import com.guiying.module.common.base.ViewManager; +import com.guiying.module.common.utils.ToastUtils; + +/** + *

类说明

+ * + * @author 张华洋 2017/7/1 13:13 + * @version V1.2.0 + * @name MainActivity + */ +public class MainActivity extends BaseActivity implements View.OnClickListener { + + private long mExitTime = 0; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + findViewById(R.id.news_button).setOnClickListener(this); + findViewById(R.id.girls_button).setOnClickListener(this); + findViewById(R.id.fragment_button).setOnClickListener(this); + } + + @Override + public void onClick(View view) { + if (view.getId() == R.id.news_button) { + //跳转到NewsCenterActivity + ARouter.getInstance().build("/news/center").navigation(); + } else if (view.getId() == R.id.girls_button) { + //跳转到GirlsActivity + ARouter.getInstance().build("/girls/list").navigation(); + } else if (view.getId() == R.id.fragment_button) { + startActivity(new Intent(this, BottomNavigationActivity.class)); + } + } + + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN) { + //两秒之内按返回键就会退出 + if ((System.currentTimeMillis() - mExitTime) > 2000) { + ToastUtils.showShortToast(getString(R.string.app_exit_hint)); + mExitTime = System.currentTimeMillis(); + } else { + ViewManager.getInstance().exitApp(this); + } + return true; + } + return super.onKeyDown(keyCode, event); + } + +} diff --git a/main/src/main/java/debug/MainApplication.java b/module_main/src/main/java/debug/MainApplication.java similarity index 87% rename from main/src/main/java/debug/MainApplication.java rename to module_main/src/main/java/debug/MainApplication.java index 293f166..24509f5 100644 --- a/main/src/main/java/debug/MainApplication.java +++ b/module_main/src/main/java/debug/MainApplication.java @@ -1,8 +1,8 @@ package debug; -import com.guiying.common.base.BaseApplication; -import com.guiying.common.http.HttpClient; -import com.guiying.common.http.OnResultListener; +import com.guiying.module.common.base.BaseApplication; +import com.guiying.module.common.http.HttpClient; +import com.guiying.module.common.http.OnResultListener; import com.orhanobut.logger.Logger; /** diff --git a/main/src/main/debug/AndroidManifest.xml b/module_main/src/main/module/AndroidManifest.xml similarity index 83% rename from main/src/main/debug/AndroidManifest.xml rename to module_main/src/main/module/AndroidManifest.xml index fc3933a..0443b12 100644 --- a/main/src/main/debug/AndroidManifest.xml +++ b/module_main/src/main/module/AndroidManifest.xml @@ -1,6 +1,6 @@ + package="com.guiying.module.main"> - + @@ -18,4 +18,4 @@ - \ No newline at end of file + diff --git a/module_main/src/main/res/drawable/ic_dashboard_black_24dp.xml b/module_main/src/main/res/drawable/ic_dashboard_black_24dp.xml new file mode 100644 index 0000000..ae6a446 --- /dev/null +++ b/module_main/src/main/res/drawable/ic_dashboard_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/module_main/src/main/res/drawable/ic_home_black_24dp.xml b/module_main/src/main/res/drawable/ic_home_black_24dp.xml new file mode 100644 index 0000000..0c36320 --- /dev/null +++ b/module_main/src/main/res/drawable/ic_home_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/module_main/src/main/res/drawable/ic_notifications_black_24dp.xml b/module_main/src/main/res/drawable/ic_notifications_black_24dp.xml new file mode 100644 index 0000000..0262382 --- /dev/null +++ b/module_main/src/main/res/drawable/ic_notifications_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/module_main/src/main/res/layout/activity_bottom_navigation.xml b/module_main/src/main/res/layout/activity_bottom_navigation.xml new file mode 100644 index 0000000..060e7be --- /dev/null +++ b/module_main/src/main/res/layout/activity_bottom_navigation.xml @@ -0,0 +1,24 @@ + + + + + + + + diff --git a/main/src/main/res/layout/activity_main.xml b/module_main/src/main/res/layout/activity_main.xml similarity index 79% rename from main/src/main/res/layout/activity_main.xml rename to module_main/src/main/res/layout/activity_main.xml index e5e21fe..c4c16f8 100644 --- a/main/src/main/res/layout/activity_main.xml +++ b/module_main/src/main/res/layout/activity_main.xml @@ -9,7 +9,7 @@ android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" - tools:context="com.guiying.main.MainActivity"> + tools:context="com.guiying.module.main.MainActivity">