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 052995d..438a057 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,72 @@ + +# 应用截图 + + + + + + + +
+ # 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. 配置整个项目的Gradle脚本,例如 混淆、签名等; +2. app组件中可以初始化全局的库,例如Lib.init(this); +3. 添加 multiDex 功能 +4. 业务组件管理(组装); + +### main组件功能(业务组件): +1. 声明应用的launcherActivity----->android.intent.category.LAUNCHER; +2. 添加SplashActivity; +3. 添加LoginActivity; +4. 添加MainActivity; + +### girls/news组件功能(业务组件): +1. 这两个组件都是业务组件,根据产品的业务逻辑独立成一个组件; + +### common组件功能(功能组件): +1. common组件是基础库,添加一些公用的类; +2. 例如:网络请求、图片加载、工具类、base类等等; +3. 声明APP需要的uses-permission; +4. 定义全局通用的主题(Theme); + +## License + + Copyright 2017 guiying712, AndroidModulePattern Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/app/build.gradle b/app/build.gradle deleted file mode 100644 index cbe047f..0000000 --- a/app/build.gradle +++ /dev/null @@ -1,63 +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(':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 e90ddfb..0000000 --- a/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/java/com/guiying/androidmodulepattern/AppModule.java b/app/src/main/java/com/guiying/androidmodulepattern/AppModule.java deleted file mode 100644 index 08257b5..0000000 --- a/app/src/main/java/com/guiying/androidmodulepattern/AppModule.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 AppModule { -} diff --git a/app/src/main/java/com/guiying/androidmodulepattern/MainActivity.java b/app/src/main/java/com/guiying/androidmodulepattern/MainActivity.java deleted file mode 100644 index b751ae9..0000000 --- a/app/src/main/java/com/guiying/androidmodulepattern/MainActivity.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.guiying.androidmodulepattern; - -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/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml deleted file mode 100644 index 1c37bea..0000000 --- a/app/src/main/res/values/strings.xml +++ /dev/null @@ -1,8 +0,0 @@ - - 组件化项目 - - module - - 再按一次退出程序哦~ - - diff --git a/build.gradle b/build.gradle index 15257b7..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.2.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.3.8" - 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 19d2195..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 7c0f4c1..0000000 --- a/common/src/main/java/com/guiying/common/base/BaseActionBarActivity.java +++ /dev/null @@ -1,46 +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()); - } - } - - @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 b5d76a4..0000000 --- a/common/src/main/java/com/guiying/common/base/BaseActivity.java +++ /dev/null @@ -1,48 +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.AppCompatActivity; -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()); - } - } - - @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 68cc1c2..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=false \ 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/lib_common/src/main/java/com/guiying/module/common/base/InfoCallback.java b/lib_common/src/main/java/com/guiying/module/common/base/InfoCallback.java new file mode 100644 index 0000000..8a5cf9b --- /dev/null +++ b/lib_common/src/main/java/com/guiying/module/common/base/InfoCallback.java @@ -0,0 +1,19 @@ +package com.guiying.module.common.base; + +import android.support.annotation.Keep; + +/** + *

数据回调接口

+ * + * @author 张华洋 2017/3/22 13:36 + * @version V1.2.0 + * @name InfoCallback + */ +@Keep +public interface InfoCallback { + + void onSuccess(T info); + + void onError(int code, String message); + +} 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 51% 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 3bfefbb..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,67 +1,82 @@ -package com.guiying.common.base; +package com.guiying.module.common.base; import android.app.Activity; -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必须在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 */ @@ -70,6 +85,7 @@ public void finishActivity() { finishActivity(activity); } + /** * 结束指定的Activity */ @@ -81,6 +97,7 @@ public void finishActivity(Activity activity) { } } + /** * 结束指定Class的Activity */ @@ -93,6 +110,7 @@ public void finishActivity(Class cls) { } } + /** * 结束全部的Activity */ @@ -105,19 +123,19 @@ public void finishAllActivity() { activityStack.clear(); } + /** * 退出应用程序 */ public void exitApp(Context context) { try { finishAllActivity(); - android.app.ActivityManager activityMgr = (android.app.ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); - activityMgr.restartPackage(context.getPackageName()); - System.exit(0); + //杀死后台进程需要在AndroidManifest中声明android.permission.KILL_BACKGROUND_PROCESSES; + android.app.ActivityManager activityManager = (android.app.ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); + activityManager.killBackgroundProcesses(context.getPackageName()); + //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 2713c31..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: + 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/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/app/src/main/res/values/colors.xml b/module_girls/src/main/res/values/colors.xml similarity index 100% rename from app/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/news/.gitignore b/module_main/.gitignore similarity index 100% rename from news/.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/module_main/src/main/AndroidManifest.xml b/module_main/src/main/AndroidManifest.xml new file mode 100644 index 0000000..db12695 --- /dev/null +++ b/module_main/src/main/AndroidManifest.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + \ 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/app/src/main/java/com/guiying/androidmodulepattern/MyApplication.java b/module_main/src/main/java/debug/MainApplication.java similarity index 70% rename from app/src/main/java/com/guiying/androidmodulepattern/MyApplication.java rename to module_main/src/main/java/debug/MainApplication.java index a4f3976..24509f5 100644 --- a/app/src/main/java/com/guiying/androidmodulepattern/MyApplication.java +++ b/module_main/src/main/java/debug/MainApplication.java @@ -1,21 +1,18 @@ -package com.guiying.androidmodulepattern; +package debug; -import com.github.mzule.activityrouter.annotation.Modules; -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; /** *

类说明

* - * @author 张华洋 2017/2/15 20:14 + * @author 张华洋 2017/2/15 20:09 * @version V1.2.0 - * @name MyApplication + * @name GirlsApplication */ -@Modules({"app", "girls", "news"}) -public class MyApplication extends BaseApplication { - +public class MainApplication extends BaseApplication { @Override public void onCreate() { diff --git a/news/src/main/debug/AndroidManifest.xml b/module_main/src/main/module/AndroidManifest.xml similarity index 68% rename from news/src/main/debug/AndroidManifest.xml rename to module_main/src/main/module/AndroidManifest.xml index 43b815b..0443b12 100644 --- a/news/src/main/debug/AndroidManifest.xml +++ b/module_main/src/main/module/AndroidManifest.xml @@ -1,17 +1,15 @@ + package="com.guiying.module.main"> - + @@ -19,4 +17,5 @@ - \ 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/app/src/main/res/layout/activity_main.xml b/module_main/src/main/res/layout/activity_main.xml similarity index 79% rename from app/src/main/res/layout/activity_main.xml rename to module_main/src/main/res/layout/activity_main.xml index 9e0fb9f..c4c16f8 100644 --- a/app/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.androidmodulepattern.MainActivity"> + tools:context="com.guiying.module.main.MainActivity">