[
  {
    "path": ".gitignore",
    "content": "# Intellij IDEA\n.idea/\n*.iml\n*.ipr\n*.iws\nout/\n\n# Gradle build folder\nbuild/\n.gradle/\n\n# Android\nlocal.properties\nbin/\ngen/\n\n# JNI compile files\n*.o\n*.o.d\n\n# OS autogen folder information\n.DS_Store\nThumbs.db\n\n# Temp files\n*.bak\n*.tmp\n*.temp\n*.swp\n*.*~\n~*.*\n\n# Eclipse project files\n.classpath\n.settings/\n.project\n\n#Android 2.2 C/C++ compile\n.externalNativeBuild/\n"
  },
  {
    "path": "README.md",
    "content": "### 简介\n路由在项目中用了很长一段时间了，一直用的ARouter，很早的时候，我就把ARouter里里外外研究了一番，可以说里面干货多多，但时间长了就有些记不住了，甚至一些技术点都记的混淆了。\n于是便萌生了写一篇技术博客的想法，后来又觉着干巴巴的写一篇文章不足以让我认识的更深刻，就想着可否按照ARouter的思想自己实现一个简单的路由框架呢？<br/>\n后来，在我不断地学习推动以及参考众多资料的情况下，耗费了几个月的业余时间，终于完成了这个项目。\n### 这个项目对你有什么帮助？\n通常看来，我要理解ARouter，就要去读ARouter的源码，这当然是不错的方法，但需要花费很多的时间去理解源码，而这个项目能给你的好处是一步步有条理的指导你如何去设计路由框架、一些技术点的作用及为什么要用这些技术等等，并且重点放在讲解，直到最后设计出来一款自己的路由框架，所以说呢，干货多多，简要列举几点：\n\n* 首先，你可以学习到如何搭建组件化架构\n\n* 其次，你可以学习到apt、javapoet等框架开发利器\n\n* 再者，你可以手动实现自己的依赖注入框架\n\n* 最后，像instantrun处理、框架设计等等\n\n### 项目理解推荐\n既然你来了，我想我们的目的很明确，就是要从根本上理解路由。所以我推荐大家把demo clone下来在电脑上跑一遍，然后边浏览WIKI的文档边读代码，这样才能快速的理解设计的思想。<br/>\n\n[文档指导，点击跳转wiki](https://github.com/Xiasm/EasyRouter/wiki)<br/>\n\n##### 目录：<br/>\n\n\n[一、从组件化引入路由设计需要满足的条件](https://github.com/Xiasm/EasyRouter/wiki/%E4%BB%8E%E7%BB%84%E4%BB%B6%E5%8C%96%E5%BC%95%E5%85%A5%E8%B7%AF%E7%94%B1%E8%AE%BE%E8%AE%A1%E9%9C%80%E8%A6%81%E6%BB%A1%E8%B6%B3%E7%9A%84%E6%9D%A1%E4%BB%B6)\n\n[二、通过Route注解去探究如何实现路由跳转](https://github.com/Xiasm/EasyRouter/wiki/%E9%80%9A%E8%BF%87Route%E6%B3%A8%E8%A7%A3%E5%8E%BB%E6%8E%A2%E7%A9%B6%E5%A6%82%E4%BD%95%E5%AE%9E%E7%8E%B0%E8%B7%AF%E7%94%B1%E8%B7%B3%E8%BD%AC)\n<br/>\n\n[三、利用apt和javapoet生成路由映射文件](https://github.com/Xiasm/EasyRouter/wiki/%E5%88%A9%E7%94%A8apt%E5%92%8Cjavapoet%E7%94%9F%E6%88%90%E8%B7%AF%E7%94%B1%E6%98%A0%E5%B0%84%E6%96%87%E4%BB%B6)\n<br/>\n\n[四、框架的设计](https://github.com/Xiasm/EasyRouter/wiki/%E6%A1%86%E6%9E%B6%E7%9A%84%E8%AE%BE%E8%AE%A1)\n<br/>\n\n[五、框架的初始化](https://github.com/Xiasm/EasyRouter/wiki/%E6%A1%86%E6%9E%B6%E7%9A%84%E5%88%9D%E5%A7%8B%E5%8C%96)\n<br/>\n\n[六、实现路由跳转](https://github.com/Xiasm/EasyRouter/wiki/%E5%AE%9E%E7%8E%B0%E8%B7%AF%E7%94%B1%E8%B7%B3%E8%BD%AC)\n<br/>\n\n[七、为什么需要依赖注入](https://github.com/Xiasm/EasyRouter/wiki/%E4%B8%BA%E4%BB%80%E4%B9%88%E9%9C%80%E8%A6%81%E4%BE%9D%E8%B5%96%E6%B3%A8%E5%85%A5)\n\n[八、Activity的属性注入](https://github.com/Xiasm/EasyRouter/wiki/Activity%E7%9A%84%E5%B1%9E%E6%80%A7%E6%B3%A8%E5%85%A5)\n<br/>\n\n### 联系我\n\nemail:xiasem@163.com & devxiasm@gmail.com<br/>\n微信：xsm0824mn003\n"
  },
  {
    "path": "app/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "app/build.gradle",
    "content": "apply plugin: 'com.android.application'\n\ndef cfg = rootProject.ext.android\ndef appId = rootProject.ext.appId\n\nandroid {\n    compileSdkVersion 26\n    defaultConfig {\n        applicationId appId[\"app\"]\n        minSdkVersion cfg.minSdkVersion\n        targetSdkVersion cfg.targetSdkVersion\n        versionCode cfg.versionCode\n        versionName cfg.versionName\n\n        testInstrumentationRunner \"android.support.test.runner.AndroidJUnitRunner\"\n\n        javaCompileOptions {\n            annotationProcessorOptions {\n                arguments = [moduleName: project.getName()]\n            }\n        }\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n}\n\ndependencies {\n    implementation fileTree(include: ['*.jar'], dir: 'libs')\n    implementation 'com.android.support.constraint:constraint-layout:1.0.2'\n    testImplementation 'junit:junit:4.12'\n    androidTestImplementation 'com.android.support.test:runner:1.0.1'\n    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'\n\n    annotationProcessor project(':easy-compiler')\n    implementation project(':base')\n\n    if (isModule) {\n        implementation project(':module1')\n        implementation project(':module2')\n    }\n}\n"
  },
  {
    "path": "app/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "app/src/androidTest/java/com/xsm/easyrouter/ExampleInstrumentedTest.java",
    "content": "package com.xsm.easyrouter;\n\nimport android.content.Context;\nimport android.support.test.InstrumentationRegistry;\nimport android.support.test.runner.AndroidJUnit4;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\nimport static org.junit.Assert.*;\n\n/**\n * Instrumented test, which will execute on an Android device.\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\n@RunWith(AndroidJUnit4.class)\npublic class ExampleInstrumentedTest {\n    @Test\n    public void useAppContext() throws Exception {\n        // Context of the app under test.\n        Context appContext = InstrumentationRegistry.getTargetContext();\n\n        assertEquals(\"com.xsm.easyrouter\", appContext.getPackageName());\n    }\n}\n"
  },
  {
    "path": "app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n          package=\"com.xsm.easyrouter\">\n\n    <application\n        android:name=\".app.MyApplication\"\n        android:allowBackup=\"true\"\n        android:icon=\"@mipmap/ic_launcher\"\n        android:label=\"@string/app_name\"\n        android:roundIcon=\"@mipmap/ic_launcher_round\"\n        android:theme=\"@style/AppTheme\">\n        <activity android:name=\".MainActivity\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\"/>\n\n                <category android:name=\"android.intent.category.LAUNCHER\"/>\n            </intent-filter>\n        </activity>\n        <activity android:name=\".Main2Activity\">\n        </activity>\n        <activity android:name=\".ShowActivity\">\n        </activity>\n    </application>\n\n</manifest>"
  },
  {
    "path": "app/src/main/java/com/xsm/easyrouter/BussinessInterceptor.java",
    "content": "package com.xsm.easyrouter;\n\nimport android.content.Context;\nimport android.util.Log;\n\nimport com.xsm.easy.annotation.Interceptor;\nimport com.xsm.easy.core.Postcard;\nimport com.xsm.easy.core.callback.InterceptorCallback;\nimport com.xsm.easy.core.template.IInterceptor;\n\n/**\n * @author: luoxiaohui\n * @date: 2019-06-18 18:02\n * @desc:\n */\n@Interceptor(priority = 2, name = \"test\")\npublic class BussinessInterceptor implements IInterceptor {\n\n    private static final String TAG = \"BussinessInterceptor\";\n\n    /**\n     * 拦截器流程\n     *\n     * @param postcard\n     * @param callback\n     * @author luoxiaohui\n     * @createTime 2019-05-23 20:53\n     */\n    @Override\n    public void process(Postcard postcard, InterceptorCallback callback) {\n\n        Log.e(TAG, \"process()...\");\n        callback.onNext(postcard);\n    }\n\n    /**\n     * 在调用EasyRouter.init()初始化时，会调用到此方法\n     *\n     * @param context\n     * @author luoxiaohui\n     * @createTime 2019-06-18 10:39\n     */\n    @Override\n    public void init(Context context) {\n\n        Log.e(TAG, \"init()...\");\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/xsm/easyrouter/Main2Activity.java",
    "content": "package com.xsm.easyrouter;\n\nimport android.support.v7.app.AppCompatActivity;\nimport android.os.Bundle;\n\nimport com.xsm.easy.annotation.Route;\n\n@Route(path = \"/main/main2\")\npublic class Main2Activity extends AppCompatActivity {\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_main2);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/xsm/easyrouter/MainActivity.java",
    "content": "package com.xsm.easyrouter;\n\nimport android.support.v7.app.AppCompatActivity;\nimport android.os.Bundle;\nimport android.util.Log;\nimport android.view.View;\nimport android.widget.Toast;\n\nimport com.xsm.base.providers.module1.Module1Providers;\nimport com.xsm.easy.annotation.Route;\nimport com.xsm.easy.core.EasyRouter;\nimport com.xsm.easy.core.Postcard;\nimport com.xsm.easy.core.callback.NavigationCallback;\n\n@Route(path = \"/main/main\")\npublic class MainActivity extends AppCompatActivity {\n\n    private static final String TAG = \"MainActivity\";\n    private Module1Providers module1Providers;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_main);\n        initProviders();\n    }\n\n    private void initProviders() {\n        module1Providers = (Module1Providers) EasyRouter.getsInstance().build(\"/module1/providers\").navigation();\n    }\n\n    public void startModule1MainActivity(View view) {\n//        EasyRouter.getsInstance().build(\"/module1/module1main\").navigation();\n        EasyRouter.getsInstance().build(\"/module1/module1main\")\n                .withString(\"msg\", \"从MainActivity\").navigation();\n    }\n\n    public void startModule2MainActivity(View view) {\n        EasyRouter.getsInstance().build(\"/module2/module2main\").navigation(this, new NavigationCallback() {\n            @Override\n            public void onFound(Postcard postcard) {\n\n            }\n\n            @Override\n            public void onLost(Postcard postcard) {\n\n            }\n\n            @Override\n            public void onArrival(Postcard postcard) {\n\n            }\n\n            @Override\n            public void onInterrupt(Throwable throwable) {\n\n                Log.e(TAG, throwable.getMessage());\n            }\n        });\n    }\n\n    public void add(View view) {\n        int num = module1Providers.add(5, 6);\n        Toast.makeText(this, \"5+6=\" + num, Toast.LENGTH_SHORT).show();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/xsm/easyrouter/ShowActivity.java",
    "content": "package com.xsm.easyrouter;\n\nimport android.support.v7.app.AppCompatActivity;\nimport android.os.Bundle;\n\nimport com.xsm.easy.annotation.Route;\n\n@Route(path = \"/show/info\")\npublic class ShowActivity extends AppCompatActivity {\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_show);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/xsm/easyrouter/app/MyApplication.java",
    "content": "package com.xsm.easyrouter.app;\n\nimport android.app.Application;\n\nimport com.xsm.easy.core.EasyRouter;\n\n/**\n * Author: 夏胜明\n * Date: 2018/7/30 0030\n * Email: xiasem@163.com\n * Description:\n */\npublic class MyApplication extends Application {\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n        EasyRouter.init(this);\n    }\n}\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_launcher_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportHeight=\"108\"\n    android:viewportWidth=\"108\">\n    <path\n        android:fillColor=\"#26A69A\"\n        android:pathData=\"M0,0h108v108h-108z\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M9,0L9,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,0L19,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M29,0L29,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M39,0L39,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M49,0L49,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M59,0L59,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M69,0L69,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M79,0L79,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M89,0L89,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M99,0L99,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,9L108,9\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,19L108,19\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,29L108,29\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,39L108,39\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,49L108,49\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,59L108,59\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,69L108,69\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,79L108,79\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,89L108,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,99L108,99\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,29L89,29\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,39L89,39\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,49L89,49\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,59L89,59\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,69L89,69\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,79L89,79\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M29,19L29,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M39,19L39,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M49,19L49,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M59,19L59,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M69,19L69,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M79,19L79,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable-v24/ic_launcher_foreground.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        xmlns:aapt=\"http://schemas.android.com/aapt\"\n        android:width=\"108dp\"\n        android:height=\"108dp\"\n        android:viewportHeight=\"108\"\n        android:viewportWidth=\"108\">\n    <path\n        android:fillType=\"evenOdd\"\n        android:pathData=\"M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z\"\n        android:strokeColor=\"#00000000\"\n        android:strokeWidth=\"1\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                android:endX=\"78.5885\"\n                android:endY=\"90.9159\"\n                android:startX=\"48.7653\"\n                android:startY=\"61.0927\"\n                android:type=\"linear\">\n                <item\n                    android:color=\"#44000000\"\n                    android:offset=\"0.0\"/>\n                <item\n                    android:color=\"#00000000\"\n                    android:offset=\"1.0\"/>\n            </gradient>\n        </aapt:attr>\n    </path>\n    <path\n        android:fillColor=\"#FFFFFF\"\n        android:fillType=\"nonZero\"\n        android:pathData=\"M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z\"\n        android:strokeColor=\"#00000000\"\n        android:strokeWidth=\"1\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/layout/activity_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    tools:context=\"com.xsm.easyrouter.MainActivity\">\n\n    <Button\n        android:onClick=\"startModule1MainActivity\"\n        android:text=\"跳转Module1主Activity\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"/>\n\n    <Button\n        android:onClick=\"startModule2MainActivity\"\n        android:text=\"跳转Module2主Activity\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"/>\n\n    <Button\n        android:text=\"加法\"\n        android:onClick=\"add\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\" />\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/activity_main2.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <TextView\n        android:text=\"main 2\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\" />\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/activity_show.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\" android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <TextView\n        android:text=\"show\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\" />\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/ic_launcher_background\"/>\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\"/>\n</adaptive-icon>"
  },
  {
    "path": "app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/ic_launcher_background\"/>\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\"/>\n</adaptive-icon>"
  },
  {
    "path": "app/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"colorPrimary\">#3F51B5</color>\n    <color name=\"colorPrimaryDark\">#303F9F</color>\n    <color name=\"colorAccent\">#FF4081</color>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">EasyRouter</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/styles.xml",
    "content": "<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.DarkActionBar\">\n        <!-- Customize your theme here. -->\n        <item name=\"colorPrimary\">@color/colorPrimary</item>\n        <item name=\"colorPrimaryDark\">@color/colorPrimaryDark</item>\n        <item name=\"colorAccent\">@color/colorAccent</item>\n    </style>\n\n</resources>\n"
  },
  {
    "path": "app/src/test/java/com/xsm/easyrouter/ExampleUnitTest.java",
    "content": "package com.xsm.easyrouter;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.*;\n\n/**\n * Example local unit test, which will execute on the development machine (host).\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\npublic class ExampleUnitTest {\n    @Test\n    public void addition_isCorrect() throws Exception {\n        assertEquals(4, 2 + 2);\n    }\n}"
  },
  {
    "path": "base/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "base/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\ndef cfg = rootProject.ext.android\ndef librarys = rootProject.ext.dependencies\n\nandroid {\n    compileSdkVersion cfg.compileSdkVersion\n\n\n\n    defaultConfig {\n        minSdkVersion cfg.minSdkVersion\n        targetSdkVersion cfg.targetSdkVersion\n        versionCode cfg.versionCode\n        versionName cfg.versionName\n\n        testInstrumentationRunner \"android.support.test.runner.AndroidJUnitRunner\"\n\n    }\n\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n\n}\n\ndependencies {\n    implementation fileTree(dir: 'libs', include: ['*.jar'])\n\n    testImplementation 'junit:junit:4.12'\n    androidTestImplementation 'com.android.support.test:runner:1.0.1'\n    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'\n\n    librarys.each { k, v -> api v }\n    api project(':easy-core')\n}\n"
  },
  {
    "path": "base/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "base/src/androidTest/java/com/xsm/base/ExampleInstrumentedTest.java",
    "content": "package com.xsm.base;\n\nimport android.content.Context;\nimport android.support.test.InstrumentationRegistry;\nimport android.support.test.runner.AndroidJUnit4;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\nimport static org.junit.Assert.*;\n\n/**\n * Instrumented test, which will execute on an Android device.\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\n@RunWith(AndroidJUnit4.class)\npublic class ExampleInstrumentedTest {\n    @Test\n    public void useAppContext() throws Exception {\n        // Context of the app under test.\n        Context appContext = InstrumentationRegistry.getTargetContext();\n\n        assertEquals(\"com.xsm.base.test\", appContext.getPackageName());\n    }\n}\n"
  },
  {
    "path": "base/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n          package=\"com.xsm.base\"/>\n"
  },
  {
    "path": "base/src/main/java/com/xsm/base/providers/module1/Module1Providers.java",
    "content": "package com.xsm.base.providers.module1;\n\nimport com.xsm.easy.core.template.IService;\n\n/**\n * Author: 夏胜明\n * Date: 2018/8/20 0020\n * Email: xiasem@163.com\n * Description:\n */\npublic interface Module1Providers extends IService {\n\n    int add(int a, int b);\n\n}\n"
  },
  {
    "path": "base/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">base</string>\n</resources>\n"
  },
  {
    "path": "base/src/test/java/com/xsm/base/ExampleUnitTest.java",
    "content": "package com.xsm.base;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.*;\n\n/**\n * Example local unit test, which will execute on the development machine (host).\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\npublic class ExampleUnitTest {\n    @Test\n    public void addition_isCorrect() throws Exception {\n        assertEquals(4, 2 + 2);\n    }\n}"
  },
  {
    "path": "build.gradle",
    "content": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\n//相当于引入头文件 将 config中的内容引入进来\napply from: \"config.gradle\"\n\nbuildscript {\n    \n    repositories {\n        google()\n        jcenter()\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:3.4.0'\n        \n\n        // NOTE: Do not place your application dependencies here; they belong\n        // in the individual module build.gradle files\n    }\n}\n\nallprojects {\n    repositories {\n        google()\n        jcenter()\n    }\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}\n"
  },
  {
    "path": "config.gradle",
    "content": "ext {\n    //true 集成模式 false 组件模式\n    isModule = true\n\n    android = [\n            compileSdkVersion:26,\n            minSdkVersion    :14,\n            targetSdkVersion :26,\n            versionCode      :1,\n            versionName      :\"1.0\"\n    ]\n\n    appId = [\n            \"app\":\"com.xsm.easyrouter\",\n            \"module1\":\"com.xsm.module1\",\n            \"module2\":\"com.xsm.module2\"\n    ]\n\n    supportLibrary = \"26.1.0\"\n\n    dependencies = [\n            \"appcompat-v7\":\"com.android.support:appcompat-v7:${supportLibrary}\"\n    ]\n\n}"
  },
  {
    "path": "easy-annotation/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "easy-annotation/build.gradle",
    "content": "apply plugin: 'java-library'\n\ndependencies {\n    implementation fileTree(dir: 'libs', include: ['*.jar'])\n}\n\nsourceCompatibility = \"1.7\"\ntargetCompatibility = \"1.7\"\n"
  },
  {
    "path": "easy-annotation/src/main/java/com/xsm/easy/annotation/Extra.java",
    "content": "package com.xsm.easy.annotation;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Author: 夏胜明\n * Date: 2018/8/20 0020\n * Email: xiasem@163.com\n * Description:\n */\n@Target({ElementType.FIELD})\n@Retention(RetentionPolicy.CLASS)\npublic @interface Extra {\n    String name() default \"\";\n}\n"
  },
  {
    "path": "easy-annotation/src/main/java/com/xsm/easy/annotation/Interceptor.java",
    "content": "package com.xsm.easy.annotation;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * @author: luoxiaohui\n * @date: 2019-05-23 20:08\n * @desc:\n */\n@Target({ElementType.TYPE})\n@Retention(RetentionPolicy.CLASS)\npublic @interface Interceptor {\n\n    /**\n     * 拦截器优先级\n     * @author luoxiaohui\n     * @createTime 2019-06-04 20:51\n     */\n    int priority();\n    /**\n     * 拦截器的名称\n     * @author luoxiaohui\n     * @createTime 2019-05-23 20:33\n     */\n    String name() default \"\";\n}\n"
  },
  {
    "path": "easy-annotation/src/main/java/com/xsm/easy/annotation/Route.java",
    "content": "package com.xsm.easy.annotation;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Author: 夏胜明\n * Date: 2018/3/29 0029\n * Email: xiasem@163.com\n * Description:\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.CLASS)\npublic @interface Route {\n    /**\n     * 路由的路径\n     * @return\n     */\n    String path();\n\n    /**\n     * 将路由节点进行分组，可以实现动态加载\n     * @return\n     */\n    String group() default \"\";\n\n}\n"
  },
  {
    "path": "easy-annotation/src/main/java/com/xsm/easy/annotation/modle/RouteMeta.java",
    "content": "package com.xsm.easy.annotation.modle;\n\nimport com.xsm.easy.annotation.Route;\n\nimport javax.lang.model.element.Element;\n\n/**\n * Author: 夏胜明\n * Date: 2018/3/29 0029\n * Email: xiasem@163.com\n * Description:\n */\n\npublic class RouteMeta {\n    public enum Type {\n        ACTIVITY,ISERVICE\n    }\n\n    private Type type;\n\n    /**\n     * 节点（Activity）\n     */\n    private Element element;\n    /**\n     * 注解使用的类对象\n     */\n    private Class<?> destination;\n\n    /**\n     * 路由地址\n     */\n    private String path;\n\n    /**\n     * 路由组\n     */\n    private String group;\n\n    public static RouteMeta build(Type type, Class<?> destination, String path, String\n            group) {\n        return new RouteMeta(type, null, destination, path, group);\n    }\n\n    public RouteMeta() {\n    }\n\n    public RouteMeta(Type type, Route route, Element element) {\n        this(type, element, null, route.path(), route.group());\n    }\n\n    public RouteMeta(Type type, Element element, Class<?> destination, String path, String\n            group) {\n        this.type = type;\n        this.destination = destination;\n        this.element = element;\n        this.path = path;\n        this.group = group;\n    }\n\n\n    public Type getType() {\n        return type;\n    }\n\n    public void setType(Type type) {\n        this.type = type;\n    }\n\n    public Element getElement() {\n        return element;\n    }\n\n    public void setElement(Element element) {\n        this.element = element;\n    }\n\n    public Class<?> getDestination() {\n        return destination;\n    }\n\n    public void setDestination(Class<?> destination) {\n        this.destination = destination;\n    }\n\n    public String getPath() {\n        return path;\n    }\n\n    public void setPath(String path) {\n        this.path = path;\n    }\n\n    public String getGroup() {\n        return group;\n    }\n\n    public void setGroup(String group) {\n        this.group = group;\n    }\n}\n"
  },
  {
    "path": "easy-compiler/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "easy-compiler/build.gradle",
    "content": "apply plugin: 'java-library'\n\ndependencies {\n    implementation fileTree(dir: 'libs', include: ['*.jar'])\n    implementation 'com.google.auto.service:auto-service:1.0-rc2'\n    annotationProcessor 'com.google.auto.service:auto-service:1.0-rc2'\n    implementation 'com.squareup:javapoet:1.7.0'\n    implementation project(':easy-annotation')\n}\n\nsourceCompatibility = \"1.7\"\ntargetCompatibility = \"1.7\"\n"
  },
  {
    "path": "easy-compiler/src/main/java/com/xsm/easy/compiler/processor/ExtraProcessor.java",
    "content": "package com.xsm.easy.compiler.processor;\n\nimport com.google.auto.service.AutoService;\nimport com.squareup.javapoet.ClassName;\nimport com.squareup.javapoet.JavaFile;\nimport com.squareup.javapoet.ParameterSpec;\nimport com.squareup.javapoet.TypeName;\nimport com.squareup.javapoet.TypeSpec;\nimport com.xsm.easy.annotation.Extra;\nimport com.xsm.easy.compiler.utils.Constant;\nimport com.xsm.easy.compiler.utils.LoadExtraBuilder;\nimport com.xsm.easy.compiler.utils.Log;\nimport com.xsm.easy.compiler.utils.Utils;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport javax.annotation.processing.AbstractProcessor;\nimport javax.annotation.processing.Filer;\nimport javax.annotation.processing.ProcessingEnvironment;\nimport javax.annotation.processing.Processor;\nimport javax.annotation.processing.RoundEnvironment;\nimport javax.annotation.processing.SupportedAnnotationTypes;\nimport javax.annotation.processing.SupportedOptions;\nimport javax.annotation.processing.SupportedSourceVersion;\nimport javax.lang.model.SourceVersion;\nimport javax.lang.model.element.Element;\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.type.TypeMirror;\nimport javax.lang.model.util.Elements;\nimport javax.lang.model.util.Types;\n\nimport static javax.lang.model.element.Modifier.PUBLIC;\n\n/**\n * Author: 夏胜明\n * Date: 2018/8/20 0020\n * Email: xiasem@163.com\n * Description:\n */\n@AutoService(Processor.class)\n@SupportedOptions(Constant.ARGUMENTS_NAME)\n@SupportedSourceVersion(SourceVersion.RELEASE_7)\n@SupportedAnnotationTypes({Constant.ANN_TYPE_EXTRA})\npublic class ExtraProcessor extends AbstractProcessor {\n\n    /**\n     * 节点工具类 (类、函数、属性都是节点)\n     */\n    private Elements elementUtils;\n\n    /**\n     * type(类信息)工具类\n     */\n    private Types typeUtils;\n    /**\n     * 类/资源生成器\n     */\n    private Filer filerUtils;\n\n    /**\n     * 记录所有需要注入的属性 key:类节点 value:需要注入的属性节点集合\n     */\n    private Map<TypeElement, List<Element>> parentAndChild = new HashMap<>();\n    private Log log;\n\n    @Override\n    public synchronized void init(ProcessingEnvironment processingEnvironment) {\n        super.init(processingEnvironment);\n        //获得apt的日志输出\n        log = Log.newLog(processingEnvironment.getMessager());\n        elementUtils = processingEnv.getElementUtils();\n        typeUtils = processingEnvironment.getTypeUtils();\n        filerUtils = processingEnv.getFiler();\n    }\n\n    @Override\n    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {\n        if (!Utils.isEmpty(set)) {\n            Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(Extra.class);\n            if (!Utils.isEmpty(elements)) {\n                try {\n                    categories(elements);\n                    generateAutoWired();\n                } catch (IOException e) {\n                    e.printStackTrace();\n                }\n                return true;\n            }\n        }\n        return false;\n    }\n\n    private void generateAutoWired() throws IOException {\n        TypeMirror typeActivity = elementUtils.getTypeElement(Constant.ACTIVITY).asType();\n        TypeElement iExtra = elementUtils.getTypeElement(Constant.IEXTRA);\n\n        if (!Utils.isEmpty(parentAndChild)) {\n            // 参数 Object target\n            ParameterSpec objectParamSpec = ParameterSpec.builder(TypeName.OBJECT, \"target\").build();\n            for (Map.Entry<TypeElement, List<Element>> entry : parentAndChild.entrySet()) {\n                TypeElement rawClassElement = entry.getKey();\n                if (!typeUtils.isSubtype(rawClassElement.asType(), typeActivity)) {\n                    throw new RuntimeException(\"just support activity filed: \" + rawClassElement);\n                }\n                //封装的函数生成类\n                LoadExtraBuilder loadExtra = new LoadExtraBuilder(objectParamSpec);\n                loadExtra.setElementUtils(elementUtils);\n                loadExtra.setTypeUtils(typeUtils);\n                ClassName className = ClassName.get(rawClassElement);\n                loadExtra.injectTarget(className);\n                //遍历属性\n                for (int i = 0; i < entry.getValue().size(); i++) {\n                    Element element = entry.getValue().get(i);\n                    loadExtra.buildStatement(element);\n                }\n\n                // 生成java类名\n                String extraClassName = rawClassElement.getSimpleName() + Constant.NAME_OF_EXTRA;\n                // 生成 XX$$Autowired\n                JavaFile.builder(className.packageName(), TypeSpec.classBuilder(extraClassName)\n                        .addSuperinterface(ClassName.get(iExtra))\n                        .addModifiers(PUBLIC).addMethod(loadExtra.build()).build())\n                        .build().writeTo(filerUtils);\n                log.i(\"Generated Extra: \" + className.packageName() + \".\" + extraClassName);\n            }\n        }\n    }\n\n    /**\n     * 记录需要生成的类与属性\n     *\n     * @param elements\n     * @throws IllegalAccessException\n     */\n    private void categories(Set<? extends Element> elements) {\n        for (Element element : elements) {\n            //获得父节点 (类)\n            TypeElement enclosingElement = (TypeElement) element.getEnclosingElement();\n            if (parentAndChild.containsKey(enclosingElement)) {\n                parentAndChild.get(enclosingElement).add(element);\n            } else {\n                List<Element> childs = new ArrayList<>();\n                childs.add(element);\n                parentAndChild.put(enclosingElement, childs);\n            }\n        }\n    }\n\n\n}\n"
  },
  {
    "path": "easy-compiler/src/main/java/com/xsm/easy/compiler/processor/InterceptorProcessor.java",
    "content": "package com.xsm.easy.compiler.processor;\n\nimport com.google.auto.service.AutoService;\nimport com.squareup.javapoet.ClassName;\nimport com.squareup.javapoet.JavaFile;\nimport com.squareup.javapoet.MethodSpec;\nimport com.squareup.javapoet.ParameterSpec;\nimport com.squareup.javapoet.ParameterizedTypeName;\nimport com.squareup.javapoet.TypeSpec;\nimport com.squareup.javapoet.WildcardTypeName;\nimport com.xsm.easy.annotation.Interceptor;\nimport com.xsm.easy.compiler.utils.Constant;\nimport com.xsm.easy.compiler.utils.Log;\nimport com.xsm.easy.compiler.utils.Utils;\n\nimport java.io.IOException;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\n\nimport javax.annotation.processing.AbstractProcessor;\nimport javax.annotation.processing.Filer;\nimport javax.annotation.processing.ProcessingEnvironment;\nimport javax.annotation.processing.Processor;\nimport javax.annotation.processing.RoundEnvironment;\nimport javax.annotation.processing.SupportedAnnotationTypes;\nimport javax.annotation.processing.SupportedOptions;\nimport javax.annotation.processing.SupportedSourceVersion;\nimport javax.lang.model.SourceVersion;\nimport javax.lang.model.element.Element;\nimport javax.lang.model.element.Modifier;\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.type.TypeMirror;\nimport javax.lang.model.util.Elements;\nimport javax.lang.model.util.Types;\n\n/**\n * @author: luoxiaohui\n * @date: 2019-05-23 19:48\n * @desc: 拦截器\n */\n@AutoService(Processor.class)\n@SupportedOptions(Constant.ARGUMENTS_NAME)\n@SupportedSourceVersion(SourceVersion.RELEASE_7)\n@SupportedAnnotationTypes(Constant.ANNOTATION_TYPE_INTERCEPTOR)\npublic class InterceptorProcessor extends AbstractProcessor {\n\n    private Map<Integer, Element> interceptors = new HashMap<>();\n    /**\n     * 节点工具类 (类、函数、属性都是节点)\n     */\n    private Elements elementUtils;\n\n    /**\n     * type(类信息)工具类\n     */\n    private Types typeUtils;\n\n    /**\n     * 文件生成器 类/资源\n     */\n    private Filer filerUtils;\n\n    private TypeMirror iInterceptor;\n    private Log log;\n    private String moduleName = \"\";\n\n    @Override\n    public synchronized void init(ProcessingEnvironment processingEnv) {\n        super.init(processingEnv);\n        log = Log.newLog(processingEnv.getMessager());\n        elementUtils = processingEnv.getElementUtils();\n        typeUtils = processingEnv.getTypeUtils();\n        filerUtils = processingEnv.getFiler();\n        iInterceptor = elementUtils.getTypeElement(Constant.IINTERCEPTOR).asType();\n\n        Map<String, String> options = processingEnv.getOptions();\n        if (!Utils.isEmpty(options)) {\n            moduleName = options.get(Constant.ARGUMENTS_NAME);\n        }\n    }\n\n    /**\n     * {@inheritDoc}\n     *\n     * @param annotations\n     * @param roundEnv\n     */\n    @Override\n    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {\n        if (!Utils.isEmpty(annotations)) {\n            Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(Interceptor.class);\n            try {\n                parseInterceptor(elements);\n            } catch (Exception e) {\n                log.i(e.getMessage());\n            }\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * 解析拦截器\n     *\n     * @author luoxiaohui\n     * @createTime 2019-05-23 20:12\n     */\n    private void parseInterceptor(Set<? extends Element> elements) throws IOException {\n        if (!Utils.isEmpty(elements)) {\n\n            for (Element element : elements) {\n                if (verify(element)) {\n\n                    Interceptor interceptor = element.getAnnotation(Interceptor.class);\n                    interceptors.put(interceptor.priority(), element);\n                }\n            }\n\n            TypeElement iInterceptor = elementUtils.getTypeElement(Constant.IINTERCEPTOR);\n            TypeElement iInterceptorGroup = elementUtils.getTypeElement(Constant.IINTERCEPTOR_GROUP);\n            /**\n             * Map<String, Class<? extends IInterceptor></>>\n             */\n            ParameterizedTypeName parameterizedTypeName = ParameterizedTypeName.get(\n                    ClassName.get(Map.class),\n                    ClassName.get(Integer.class),\n                    ParameterizedTypeName.get(\n                            ClassName.get(Class.class),\n                            WildcardTypeName.subtypeOf(ClassName.get(iInterceptor))\n                    )\n            );\n            /**\n             * 参数+变量名\n             * Map<String, Class<? extends IInterceptor>> interceptors\n             */\n            ParameterSpec parameterSpec = ParameterSpec.builder(parameterizedTypeName, \"interceptors\").build();\n            /**\n             * 构建方法\n             * public void loadInto(Map<String, Class<? extends IInterceptor>> interceptors){}\n             */\n            MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder(Constant.METHOD_LOAD_INTO)\n                    .addAnnotation(Override.class)\n                    .addModifiers(Modifier.PUBLIC)\n                    .addParameter(parameterSpec);\n            if (!interceptors.isEmpty() && interceptors.size() > 0) {\n                /**\n                 * 构建方法体中的语句\n                 */\n                for (Map.Entry<Integer, Element> entry : interceptors.entrySet()) {\n                    methodBuilder.addStatement(\"interceptors.put(\" + entry.getKey() + \", $T.class)\",\n                            ClassName.get((TypeElement) entry.getValue()));\n                }\n            }\n            /**\n             * 将文件写入磁盘中\n             * 路径是在app/build/source/api/debug/PACKAGE_OF_GENERATE_FILE下面\n             */\n            JavaFile.builder(Constant.PACKAGE_OF_GENERATE_FILE,\n                    TypeSpec.classBuilder(Constant.NAME_OF_INTERCEPTOR + moduleName)\n                            .addModifiers(Modifier.PUBLIC)\n                            .addMethod(methodBuilder.build())\n                            .addSuperinterface(ClassName.get(iInterceptorGroup))\n                            .build()\n            ).build().writeTo(filerUtils);\n        }\n    }\n\n    /**\n     * 验证节点是否含有拦截器注解\n     *\n     * @author luoxiaohui\n     * @createTime 2019-05-23 20:21\n     */\n    private boolean verify(Element element) {\n\n        Interceptor interceptor = element.getAnnotation(Interceptor.class);\n        return interceptor != null && ((TypeElement) element).getInterfaces().contains(iInterceptor);\n    }\n}\n"
  },
  {
    "path": "easy-compiler/src/main/java/com/xsm/easy/compiler/processor/RouterProcessor.java",
    "content": "package com.xsm.easy.compiler.processor;\n\nimport com.google.auto.service.AutoService;\nimport com.squareup.javapoet.ClassName;\nimport com.squareup.javapoet.JavaFile;\nimport com.squareup.javapoet.MethodSpec;\nimport com.squareup.javapoet.ParameterSpec;\nimport com.squareup.javapoet.ParameterizedTypeName;\nimport com.squareup.javapoet.TypeSpec;\nimport com.squareup.javapoet.WildcardTypeName;\nimport com.xsm.easy.annotation.Route;\nimport com.xsm.easy.annotation.modle.RouteMeta;\nimport com.xsm.easy.compiler.utils.Constant;\nimport com.xsm.easy.compiler.utils.Log;\nimport com.xsm.easy.compiler.utils.Utils;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.TreeMap;\n\nimport javax.annotation.processing.AbstractProcessor;\nimport javax.annotation.processing.Filer;\nimport javax.annotation.processing.ProcessingEnvironment;\nimport javax.annotation.processing.Processor;\nimport javax.annotation.processing.RoundEnvironment;\nimport javax.annotation.processing.SupportedAnnotationTypes;\nimport javax.annotation.processing.SupportedOptions;\nimport javax.annotation.processing.SupportedSourceVersion;\nimport javax.lang.model.SourceVersion;\nimport javax.lang.model.element.Element;\nimport javax.lang.model.element.Modifier;\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.type.TypeMirror;\nimport javax.lang.model.util.Elements;\nimport javax.lang.model.util.Types;\n\n/**\n * Author: 夏胜明\n * Date: 2018/3/29 0029\n * Email: xiasem@163.com\n * Description:\n */\n\n@AutoService(Processor.class)\n/**\n  处理器接收的参数 替代 {@link AbstractProcessor#getSupportedOptions()} 函数\n */\n@SupportedOptions(Constant.ARGUMENTS_NAME)\n/**\n * 指定使用的Java版本 替代 {@link AbstractProcessor#getSupportedSourceVersion()} 函数\n */\n@SupportedSourceVersion(SourceVersion.RELEASE_7)\n/**\n * 注册给哪些注解的  替代 {@link AbstractProcessor#getSupportedAnnotationTypes()} 函数\n */\n@SupportedAnnotationTypes(Constant.ANNOTATION_TYPE_ROUTE)\n\npublic class RouterProcessor extends AbstractProcessor {\n    /**\n     * key:组名 value:类名\n     */\n    private Map<String, String> rootMap = new TreeMap<>();\n    /**\n     * 分组 key:组名 value:对应组的路由信息\n     */\n    private Map<String, List<RouteMeta>> groupMap = new HashMap<>();\n\n    /**\n     * 节点工具类 (类、函数、属性都是节点)\n     */\n    private Elements elementUtils;\n\n    /**\n     * type(类信息)工具类\n     */\n    private Types typeUtils;\n\n    /**\n     * 文件生成器 类/资源\n     */\n    private Filer filerUtils;\n\n    private String moduleName;\n\n    private Log log;\n\n    @Override\n    public synchronized void init(ProcessingEnvironment processingEnvironment) {\n        super.init(processingEnvironment);\n        //获得apt的日志输出\n        log = Log.newLog(processingEnvironment.getMessager());\n        elementUtils = processingEnvironment.getElementUtils();\n        typeUtils = processingEnvironment.getTypeUtils();\n        filerUtils = processingEnvironment.getFiler();\n\n        //参数是模块名 为了防止多模块/组件化开发的时候 生成相同的 xx$$ROOT$$文件\n        Map<String, String> options = processingEnvironment.getOptions();\n        if (!Utils.isEmpty(options)) {\n            moduleName = options.get(Constant.ARGUMENTS_NAME);\n        }\n        if (Utils.isEmpty(moduleName)) {\n            throw new RuntimeException(\"Not set processor moudleName option !\");\n        }\n        log.i(\"init RouterProcessor \" + moduleName + \" success !\");\n    }\n\n    /**\n     *\n     * @param set 使用了支持处理注解的节点集合\n     * @param roundEnvironment 表示当前或是之前的运行环境,可以通过该对象查找找到的注解。\n     * @return true 表示后续处理器不会再处理(已经处理)\n     */\n    @Override\n    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {\n        if (!Utils.isEmpty(set)) {\n            //被Route注解的节点集合\n            Set<? extends Element> rootElements = roundEnvironment.getElementsAnnotatedWith(Route.class);\n            if (!Utils.isEmpty(rootElements)) {\n                processorRoute(rootElements);\n            }\n            return true;\n        }\n        return false;\n    }\n\n    private void processorRoute(Set<? extends Element> rootElements) {\n        //获得Activity这个类的节点信息\n        TypeElement activity = elementUtils.getTypeElement(Constant.ACTIVITY);\n        TypeElement service = elementUtils.getTypeElement(Constant.ISERVICE);\n        for (Element element : rootElements) {\n            RouteMeta routeMeta;\n            //类信息\n            TypeMirror typeMirror = element.asType();\n            log.i(\"Route class:\" + typeMirror.toString());\n            Route route = element.getAnnotation(Route.class);\n            if (typeUtils.isSubtype(typeMirror, activity.asType())) {\n                routeMeta = new RouteMeta(RouteMeta.Type.ACTIVITY, route, element);\n            } else if (typeUtils.isSubtype(typeMirror, service.asType())) {\n                routeMeta = new RouteMeta(RouteMeta.Type.ISERVICE, route, element);\n            } else {\n                throw new RuntimeException(\"Just support Activity or IService Route: \" + element);\n            }\n            categories(routeMeta);\n        }\n        TypeElement iRouteGroup = elementUtils.getTypeElement(Constant.IROUTE_GROUP);\n        TypeElement iRouteRoot = elementUtils.getTypeElement(Constant.IROUTE_ROOT);\n\n        //生成Group记录分组表\n        generatedGroup(iRouteGroup);\n\n        //生成Root类 作用：记录<分组，对应的Group类>\n        generatedRoot(iRouteRoot, iRouteGroup);\n    }\n\n    /**\n     * 生成Root类  作用：记录<分组，对应的Group类>\n     * @param iRouteRoot\n     * @param iRouteGroup\n     */\n    private void generatedRoot(TypeElement iRouteRoot, TypeElement iRouteGroup) {\n        //创建参数类型 Map<String,Class<? extends IRouteGroup>> routes>\n        //Wildcard 通配符\n        ParameterizedTypeName parameterizedTypeName = ParameterizedTypeName.get(\n                ClassName.get(Map.class),\n                ClassName.get(String.class),\n                ParameterizedTypeName.get(\n                        ClassName.get(Class.class),\n                        WildcardTypeName.subtypeOf(ClassName.get(iRouteGroup))\n                ));\n        //参数 Map<String,Class<? extends IRouteGroup>> routes> routes\n        ParameterSpec parameter = ParameterSpec.builder(parameterizedTypeName, \"routes\").build();\n        //函数 public void loadInfo(Map<String,Class<? extends IRouteGroup>> routes> routes)\n        MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder(Constant.METHOD_LOAD_INTO)\n                .addModifiers(Modifier.PUBLIC)\n                .addAnnotation(Override.class)\n                .addParameter(parameter);\n        //函数体\n        for (Map.Entry<String, String> entry : rootMap.entrySet()) {\n            methodBuilder.addStatement(\"routes.put($S, $T.class)\", entry.getKey(), ClassName.get(Constant.PACKAGE_OF_GENERATE_FILE, entry.getValue()));\n        }\n        //生成$Root$类\n        String className = Constant.NAME_OF_ROOT + moduleName;\n        TypeSpec typeSpec = TypeSpec.classBuilder(className)\n                .addSuperinterface(ClassName.get(iRouteRoot))\n                .addModifiers(Modifier.PUBLIC)\n                .addMethod(methodBuilder.build())\n                .build();\n        try {\n            JavaFile.builder(Constant.PACKAGE_OF_GENERATE_FILE, typeSpec).build().writeTo(filerUtils);\n            log.i(\"Generated RouteRoot：\" + Constant.PACKAGE_OF_GENERATE_FILE + \".\" + className);\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n\n    private void generatedGroup(TypeElement iRouteGroup) {\n        //创建参数类型 Map<String, RouteMeta>\n        ParameterizedTypeName parameterizedTypeName = ParameterizedTypeName.get(\n                ClassName.get(Map.class),\n                ClassName.get(String.class),\n                ClassName.get(RouteMeta.class));\n        ParameterSpec altas = ParameterSpec.builder(parameterizedTypeName, \"atlas\").build();\n\n        for (Map.Entry<String, List<RouteMeta>> entry : groupMap.entrySet()) {\n            MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder(Constant.METHOD_LOAD_INTO)\n                    .addModifiers(Modifier.PUBLIC)\n                    .addAnnotation(Override.class)\n                    .addParameter(altas);\n\n            String groupName = entry.getKey();\n            List<RouteMeta> groupData = entry.getValue();\n            for (RouteMeta routeMeta : groupData) {\n                //函数体的添加\n                methodBuilder.addStatement(\"atlas.put($S,$T.build($T.$L,$T.class,$S,$S))\",\n                        routeMeta.getPath(),\n                        ClassName.get(RouteMeta.class),\n                        ClassName.get(RouteMeta.Type.class),\n                        routeMeta.getType(),\n                        ClassName.get(((TypeElement) routeMeta.getElement())),\n                        routeMeta.getPath(),\n                        routeMeta.getGroup());\n            }\n            String groupClassName = Constant.NAME_OF_GROUP + groupName;\n            TypeSpec typeSpec = TypeSpec.classBuilder(groupClassName)\n                    .addSuperinterface(ClassName.get(iRouteGroup))\n                    .addModifiers(Modifier.PUBLIC)\n                    .addMethod(methodBuilder.build())\n                    .build();\n            JavaFile javaFile = JavaFile.builder(Constant.PACKAGE_OF_GENERATE_FILE, typeSpec).build();\n            try {\n                javaFile.writeTo(filerUtils);\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n            rootMap.put(groupName, groupClassName);\n\n        }\n    }\n\n    /**\n     * 检查是否配置 group 如果没有配置 则从path截取出组名\n     * @param routeMeta\n     */\n    private void categories(RouteMeta routeMeta) {\n        if (routeVerify(routeMeta)) {\n            log.i(\"Group : \" + routeMeta.getGroup() + \" path=\" + routeMeta.getPath());\n            //分组与组中的路由信息\n            List<RouteMeta> routeMetas = groupMap.get(routeMeta.getGroup());\n            if (Utils.isEmpty(routeMetas)) {\n                routeMetas = new ArrayList<>();\n                routeMetas.add(routeMeta);\n                groupMap.put(routeMeta.getGroup(), routeMetas);\n            } else {\n                routeMetas.add(routeMeta);\n            }\n        } else {\n            log.i(\"Group info error:\" + routeMeta.getPath());\n        }\n    }\n\n    /**\n     * 验证path路由地址的合法性\n     * @param routeMeta\n     * @return\n     */\n    private boolean routeVerify(RouteMeta routeMeta) {\n        String path = routeMeta.getPath();\n        String group = routeMeta.getGroup();\n        // 必须以 / 开头来指定路由地址\n        if (!path.startsWith(\"/\")) {\n            return false;\n        }\n        //如果group没有设置 我们从path中获得group\n        if (Utils.isEmpty(group)) {\n            String defaultGroup = path.substring(1, path.indexOf(\"/\", 1));\n            //截取出的group还是空\n            if (Utils.isEmpty(defaultGroup)) {\n                return false;\n            }\n            routeMeta.setGroup(defaultGroup);\n        }\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "easy-compiler/src/main/java/com/xsm/easy/compiler/utils/Constant.java",
    "content": "package com.xsm.easy.compiler.utils;\n\nimport com.squareup.javapoet.ClassName;\n\n/**\n * Author: 夏胜明\n * Date: 2018/3/29 0029\n * Email: xiasem@163.com\n * Description:\n */\n\npublic class Constant {\n    public static final ClassName ROUTER = ClassName.get(\"com.xsm.easy.core\", \"EasyRouter\");\n\n    public static final String ACTIVITY = \"android.app.Activity\";\n    public static final String ISERVICE = \"com.xsm.easy.core.template.IService\";\n\n    public static final String ARGUMENTS_NAME = \"moduleName\";\n    public static final String ANNOTATION_TYPE_ROUTE = \"com.xsm.easy.annotation.Route\";\n    public static final String ANN_TYPE_EXTRA = \"com.xsm.easy.annotation.Extra\";\n    public static final String ANNOTATION_TYPE_INTERCEPTOR = \"com.xsm.easy.annotation.Interceptor\";\n\n    public static final String IROUTE_GROUP = \"com.xsm.easy.core.template.IRouteGroup\";\n    public static final String IROUTE_ROOT = \"com.xsm.easy.core.template.IRouteRoot\";\n    public static final String IEXTRA = \"com.xsm.easy.core.template.IExtra\";\n    public static final String IINTERCEPTOR = \"com.xsm.easy.core.template.IInterceptor\";\n    public static final String IINTERCEPTOR_GROUP = \"com.xsm.easy.core.template.IInterceptorGroup\";\n\n    public static final String SEPARATOR = \"_\";\n    public static final String PROJECT = \"EaseRouter\";\n    public static final String NAME_OF_GROUP = PROJECT + SEPARATOR + \"Group\" + SEPARATOR;\n    public static final String NAME_OF_ROOT = PROJECT + SEPARATOR + \"Root\" + SEPARATOR;\n    public static final String PACKAGE_OF_GENERATE_FILE = \"com.xsm.easyrouter.routes\";\n\n    public static final String METHOD_LOAD_INTO = \"loadInto\";\n    public static final String METHOD_LOAD_EXTRA = \"loadExtra\";\n\n    public static final String PARCELABLE = \"android.os.Parcelable\";\n\n    private static final String LANG = \"java.lang\";\n    public static final String BYTE = LANG + \".Byte\";\n    public static final String SHORT = LANG + \".Short\";\n    public static final String INTEGER = LANG + \".Integer\";\n    public static final String LONG = LANG + \".Long\";\n    public static final String FLOAT = LANG + \".Float\";\n    public static final String DOUBEL = LANG + \".Double\";\n    public static final String BOOLEAN = LANG + \".Boolean\";\n    public static final String STRING = LANG + \".String\";\n    public static final String ARRAY = \"ARRAY\";\n\n    public static final String ARRAYLIST = \"java.util.ArrayList\";\n    public static final String LIST = \"java.util.List\";\n\n    public static final String BYTEARRAY = \"byte[]\";\n    public static final String SHORTARRAY = \"short[]\";\n    public static final String BOOLEANARRAY = \"boolean[]\";\n    public static final String CHARARRAY = \"char[]\";\n    public static final String DOUBLEARRAY = \"double[]\";\n    public static final String FLOATARRAY = \"float[]\";\n    public static final String INTARRAY = \"int[]\";\n    public static final String LONGARRAY = \"long[]\";\n    public static final String STRINGARRAY = \"java.lang.String[]\";\n\n\n    public static final String NAME_OF_EXTRA = SEPARATOR + \"Extra\";\n    public static final String NAME_OF_INTERCEPTOR = PROJECT + SEPARATOR + \"Interceptor\" + SEPARATOR;\n\n\n}\n"
  },
  {
    "path": "easy-compiler/src/main/java/com/xsm/easy/compiler/utils/LoadExtraBuilder.java",
    "content": "package com.xsm.easy.compiler.utils;\n\nimport com.squareup.javapoet.ArrayTypeName;\nimport com.squareup.javapoet.ClassName;\nimport com.squareup.javapoet.MethodSpec;\nimport com.squareup.javapoet.ParameterSpec;\nimport com.squareup.javapoet.ParameterizedTypeName;\nimport com.squareup.javapoet.TypeName;\nimport com.xsm.easy.annotation.Extra;\n\nimport java.util.List;\n\nimport javax.lang.model.element.Element;\nimport javax.lang.model.element.Modifier;\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.type.TypeKind;\nimport javax.lang.model.type.TypeMirror;\nimport javax.lang.model.util.Elements;\nimport javax.lang.model.util.Types;\n\n/**\n * Author: 夏胜明\n * Date: 2018/8/20 0020\n * Email: xiasem@163.com\n * Description:\n */\npublic class LoadExtraBuilder {\n    private static final String INJECT_TARGET = \"$T t = ($T)target\";\n    private MethodSpec.Builder builder;\n    private Elements elementUtils;\n    private Types typeUtils;\n\n    private TypeMirror parcelableType;\n    private TypeMirror iServiceType;\n\n    public LoadExtraBuilder(ParameterSpec parameterSpec) {\n        // 函数 public void loadExtra(Object target)\n        builder = MethodSpec.methodBuilder(Constant.METHOD_LOAD_EXTRA)\n                .addAnnotation(Override.class)\n                .addModifiers(Modifier.PUBLIC)\n                .addParameter(parameterSpec);\n    }\n\n    public void setElementUtils(Elements elementUtils) {\n        this.elementUtils = elementUtils;\n        parcelableType = elementUtils.getTypeElement(Constant.PARCELABLE).asType();\n        iServiceType = elementUtils.getTypeElement(Constant.ISERVICE).asType();\n    }\n\n    public void setTypeUtils(Types typeUtils) {\n        this.typeUtils = typeUtils;\n    }\n\n    public void buildStatement(Element element) {\n        TypeMirror typeMirror = element.asType();\n        int type = typeMirror.getKind().ordinal();\n        //属性名 String text 获得text\n        String fieldName = element.getSimpleName().toString();\n        //获得注解 name值\n        String extraName = element.getAnnotation(Extra.class).name();\n        extraName = Utils.isEmpty(extraName) ? fieldName : extraName;\n        String defaultValue = \"t.\" + fieldName;\n        String statement = defaultValue + \" = t.getIntent().\";\n        if (type == TypeKind.BOOLEAN.ordinal()) {\n            statement += \"getBooleanExtra($S, \" + defaultValue + \")\";\n        } else if (type == TypeKind.BYTE.ordinal()) {\n            statement += \"getByteExtra($S, \" + defaultValue + \")\";\n        } else if (type == TypeKind.SHORT.ordinal()) {\n            statement += \"getShortExtra($S, \" + defaultValue + \")\";\n        } else if (type == TypeKind.INT.ordinal()) {\n            statement += \"getIntExtra($S, \" + defaultValue + \")\";\n        } else if (type == TypeKind.LONG.ordinal()) {\n            statement += \"getLongExtra($S, \" + defaultValue + \")\";\n        } else if (type == TypeKind.CHAR.ordinal()) {\n            statement += \"getCharExtra($S, \" + defaultValue + \")\";\n        } else if (type == TypeKind.FLOAT.ordinal()) {\n            statement += \"getFloatExtra($S, \" + defaultValue + \")\";\n        } else if (type == TypeKind.DOUBLE.ordinal()) {\n            statement += \"getDoubleExtra($S, \" + defaultValue + \")\";\n        } else {\n            //数组类型\n            if (type == TypeKind.ARRAY.ordinal()) {\n                addArrayStatement(statement, fieldName, extraName, typeMirror, element);\n            } else {\n                //Object\n                addObjectStatement(statement, fieldName, extraName, typeMirror, element);\n            }\n            return;\n        }\n        builder.addStatement(statement, extraName);\n    }\n\n    /**\n     * 添加对象 String/List/Parcelable\n     *\n     * @param statement\n     * @param extraName\n     * @param typeMirror\n     * @param element\n     */\n    private void addObjectStatement(String statement, String fieldName, String extraName,\n                                    TypeMirror typeMirror,\n                                    Element element) {\n        //Parcelable\n        if (typeUtils.isSubtype(typeMirror, parcelableType)) {\n            statement += \"getParcelableExtra($S)\";\n        } else if (typeMirror.toString().equals(Constant.STRING)) {\n            statement += \"getStringExtra($S)\";\n        } else if (typeUtils.isSubtype(typeMirror, iServiceType)) {\n            statement = \"t.\" + fieldName + \" = ($T) $T.getInstance().build($S).navigation()\";\n            builder.addStatement(statement, TypeName.get(element.asType()), Constant.ROUTER, extraName);\n            return;\n        } else {\n            //List\n            TypeName typeName = ClassName.get(typeMirror);\n            //泛型\n            if (typeName instanceof ParameterizedTypeName) {\n                //list 或 arraylist\n                ClassName rawType = ((ParameterizedTypeName) typeName).rawType;\n                //泛型类型\n                List<TypeName> typeArguments = ((ParameterizedTypeName) typeName)\n                        .typeArguments;\n                if (!rawType.toString().equals(Constant.ARRAYLIST) && !rawType.toString()\n                        .equals(Constant.LIST)) {\n                    throw new RuntimeException(\"Not Support Inject Type:\" + typeMirror + \" \" +\n                            element);\n                }\n                if (typeArguments.isEmpty() || typeArguments.size() != 1) {\n                    throw new RuntimeException(\"List Must Specify Generic Type:\" + typeArguments);\n                }\n                TypeName typeArgumentName = typeArguments.get(0);\n                TypeElement typeElement = elementUtils.getTypeElement(typeArgumentName\n                        .toString());\n                // Parcelable 类型\n                if (typeUtils.isSubtype(typeElement.asType(), parcelableType)) {\n                    statement += \"getParcelableArrayListExtra($S)\";\n                } else if (typeElement.asType().toString().equals(Constant.STRING)) {\n                    statement += \"getStringArrayListExtra($S)\";\n                } else if (typeElement.asType().toString().equals(Constant.INTEGER)) {\n                    statement += \"getIntegerArrayListExtra($S)\";\n                } else {\n                    throw new RuntimeException(\"Not Support Generic Type : \" + typeMirror + \" \" +\n                            element);\n                }\n            } else {\n                throw new RuntimeException(\"Not Support Extra Type : \" + typeMirror + \" \" +\n                        element);\n            }\n        }\n        builder.addStatement(statement, extraName);\n    }\n\n    /**\n     * 添加数组\n     *\n     * @param statement\n     * @param fieldName\n     * @param typeMirror\n     * @param element\n     */\n    private void addArrayStatement(String statement, String fieldName, String extraName, TypeMirror\n            typeMirror, Element element) {\n        //数组\n        switch (typeMirror.toString()) {\n            case Constant.BOOLEANARRAY:\n                statement += \"getBooleanArrayExtra($S)\";\n                break;\n            case Constant.INTARRAY:\n                statement += \"getIntArrayExtra($S)\";\n                break;\n            case Constant.SHORTARRAY:\n                statement += \"getShortArrayExtra($S)\";\n                break;\n            case Constant.FLOATARRAY:\n                statement += \"getFloatArrayExtra($S)\";\n                break;\n            case Constant.DOUBLEARRAY:\n                statement += \"getDoubleArrayExtra($S)\";\n                break;\n            case Constant.BYTEARRAY:\n                statement += \"getByteArrayExtra($S)\";\n                break;\n            case Constant.CHARARRAY:\n                statement += \"getCharArrayExtra($S)\";\n                break;\n            case Constant.LONGARRAY:\n                statement += \"getLongArrayExtra($S)\";\n                break;\n            case Constant.STRINGARRAY:\n                statement += \"getStringArrayExtra($S)\";\n                break;\n            default:\n                //Parcelable 数组\n                String defaultValue = \"t.\" + fieldName;\n                //object数组 componentType获得object类型\n                ArrayTypeName arrayTypeName = (ArrayTypeName) ClassName.get(typeMirror);\n                TypeElement typeElement = elementUtils.getTypeElement(arrayTypeName\n                        .componentType.toString());\n                //是否为 Parcelable 类型\n                if (!typeUtils.isSubtype(typeElement.asType(), parcelableType)) {\n                    throw new RuntimeException(\"Not Support Extra Type:\" + typeMirror + \" \" +\n                            element);\n                }\n                statement = \"$T[] \" + fieldName + \" = t.getIntent()\" +\n                        \".getParcelableArrayExtra\" +\n                        \"($S)\";\n                builder.addStatement(statement, parcelableType, extraName);\n                builder.beginControlFlow(\"if( null != $L)\", fieldName);\n                statement = defaultValue + \" = new $T[\" + fieldName + \".length]\";\n                builder.addStatement(statement, arrayTypeName.componentType)\n                        .beginControlFlow(\"for (int i = 0; i < \" + fieldName + \"\" +\n                                \".length; \" +\n                                \"i++)\")\n                        .addStatement(defaultValue + \"[i] = ($T)\" + fieldName + \"[i]\",\n                                arrayTypeName.componentType)\n                        .endControlFlow();\n                builder.endControlFlow();\n                return;\n        }\n        builder.addStatement(statement, extraName);\n    }\n\n    /**\n     * 加入 $T t = ($T)target\n     *\n     * @param className\n     */\n    public void injectTarget(ClassName className) {\n        builder.addStatement(INJECT_TARGET, className, className);\n\n    }\n\n    public MethodSpec build() {\n        return builder.build();\n    }\n}\n"
  },
  {
    "path": "easy-compiler/src/main/java/com/xsm/easy/compiler/utils/Log.java",
    "content": "package com.xsm.easy.compiler.utils;\n\nimport javax.annotation.processing.Messager;\nimport javax.tools.Diagnostic;\n\n/**\n * Author: 夏胜明\n * Date: 2018/3/29 0029\n * Email: xiasem@163.com\n * Description:\n */\n\npublic class Log {\n    private Messager messager;\n\n    private Log(Messager messager) {\n        this.messager = messager;\n    }\n\n    public static Log newLog(Messager messager) {\n        return new Log(messager);\n    }\n\n    public void i(String msg) {\n        messager.printMessage(Diagnostic.Kind.NOTE, msg);\n    }\n}\n"
  },
  {
    "path": "easy-compiler/src/main/java/com/xsm/easy/compiler/utils/Utils.java",
    "content": "package com.xsm.easy.compiler.utils;\n\nimport java.util.Collection;\nimport java.util.Map;\n\n/**\n * Author: 夏胜明\n * Date: 2018/3/29 0029\n * Email: xiasem@163.com\n * Description:\n */\n\npublic class Utils {\n    public static boolean isEmpty(CharSequence cs) {\n        return cs == null || cs.length() == 0;\n    }\n\n    public static boolean isEmpty(Collection<?> coll) {\n        return coll == null || coll.isEmpty();\n    }\n\n    public static boolean isEmpty(final Map<?, ?> map) {\n        return map == null || map.isEmpty();\n    }\n}\n"
  },
  {
    "path": "easy-core/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "easy-core/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    compileSdkVersion 26\n\n\n\n    defaultConfig {\n        minSdkVersion 14\n        targetSdkVersion 26\n        versionCode 1\n        versionName \"1.0\"\n\n        testInstrumentationRunner \"android.support.test.runner.AndroidJUnitRunner\"\n\n    }\n\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n\n}\n\ndependencies {\n    implementation fileTree(dir: 'libs', include: ['*.jar'])\n\n    implementation 'com.android.support:appcompat-v7:26.1.0'\n    testImplementation 'junit:junit:4.12'\n    androidTestImplementation 'com.android.support.test:runner:1.0.1'\n    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'\n    // compile被废弃\n    // api：同compile\n    // implementation: 不会进行传递依赖\n    // 即router-annotation模块只对 本模块(router-core) 开放,\n    // 无法在 app 模块中使用\n    api project(':easy-annotation')\n}\n"
  },
  {
    "path": "easy-core/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "easy-core/src/androidTest/java/com/xsm/easy/core/ExampleInstrumentedTest.java",
    "content": "package com.xsm.easy.core;\n\nimport android.content.Context;\nimport android.support.test.InstrumentationRegistry;\nimport android.support.test.runner.AndroidJUnit4;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\nimport static org.junit.Assert.*;\n\n/**\n * Instrumented test, which will execute on an Android device.\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\n@RunWith(AndroidJUnit4.class)\npublic class ExampleInstrumentedTest {\n    @Test\n    public void useAppContext() throws Exception {\n        // Context of the app under test.\n        Context appContext = InstrumentationRegistry.getTargetContext();\n\n        assertEquals(\"com.xsm.easy.core.test\", appContext.getPackageName());\n    }\n}\n"
  },
  {
    "path": "easy-core/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n          package=\"com.xsm.easy.core\"/>\n"
  },
  {
    "path": "easy-core/src/main/java/com/xsm/easy/core/EasyRouter.java",
    "content": "package com.xsm.easy.core;\n\nimport android.app.Activity;\nimport android.app.Application;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.PackageManager;\nimport android.os.Handler;\nimport android.os.Looper;\nimport android.support.v4.app.ActivityCompat;\nimport android.text.TextUtils;\nimport android.util.Log;\n\nimport com.xsm.easy.annotation.modle.RouteMeta;\nimport com.xsm.easy.core.callback.InterceptorCallback;\nimport com.xsm.easy.core.callback.NavigationCallback;\nimport com.xsm.easy.core.exception.NoRouteFoundException;\nimport com.xsm.easy.core.implments.InterceptorImpl;\nimport com.xsm.easy.core.template.IInterceptor;\nimport com.xsm.easy.core.template.IInterceptorGroup;\nimport com.xsm.easy.core.template.IRouteGroup;\nimport com.xsm.easy.core.template.IRouteRoot;\nimport com.xsm.easy.core.template.IService;\nimport com.xsm.easy.core.utils.ClassUtils;\n\nimport java.lang.reflect.InvocationTargetException;\nimport java.util.Map;\nimport java.util.Set;\n\n/**\n * Author: 夏胜明\n * Date: 2018/4/3 0003\n * Email: xiasem@163.com\n * Description:\n */\n\npublic class EasyRouter {\n    private static final String TAG = \"EasyRouter\";\n    private static final String ROUTE_ROOT_PAKCAGE = \"com.xsm.easyrouter.routes\";\n    private static final String SDK_NAME = \"EaseRouter\";\n    private static final String SEPARATOR = \"_\";\n    private static final String SUFFIX_ROOT = \"Root\";\n    private static final String SUFFIX_INTERCEPTOR = \"Interceptor\";\n\n    private static EasyRouter sInstance;\n    private static Application mContext;\n    private Handler mHandler;\n\n    private EasyRouter() {\n        mHandler = new Handler(Looper.getMainLooper());\n    }\n\n    public static EasyRouter getsInstance() {\n        if (sInstance == null) {\n            synchronized (EasyRouter.class) {\n                if (sInstance == null) {\n                    sInstance = new EasyRouter();\n                }\n            }\n        }\n        return sInstance;\n    }\n\n    public static void init(Application application) {\n        mContext = application;\n        try {\n            loadInfo();\n            InterceptorImpl.init(application.getApplicationContext());\n        } catch (Exception e) {\n            e.printStackTrace();\n            Log.e(TAG, \"初始化失败!\", e);\n        }\n    }\n\n\n    /**\n     * 分组表制作\n     */\n    private static void loadInfo() throws PackageManager.NameNotFoundException, InterruptedException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {\n        //获得所有 apt生成的路由类的全类名 (路由表)\n        Set<String> routerMap = ClassUtils.getFileNameByPackageName(mContext, ROUTE_ROOT_PAKCAGE);\n        for (String className : routerMap) {\n            if (className.startsWith(ROUTE_ROOT_PAKCAGE + \".\" + SDK_NAME + SEPARATOR + SUFFIX_ROOT)) {\n                //root中注册的是分组信息 将分组信息加入仓库中\n                ((IRouteRoot) Class.forName(className).getConstructor().newInstance()).loadInto(Warehouse.groupsIndex);\n            } else if (className.startsWith(ROUTE_ROOT_PAKCAGE + \".\" + SDK_NAME + SEPARATOR + SUFFIX_INTERCEPTOR)) {\n\n                ((IInterceptorGroup) Class.forName(className).getConstructor().newInstance()).loadInto(Warehouse.interceptorsIndex);\n            }\n        }\n        for (Map.Entry<String, Class<? extends IRouteGroup>> stringClassEntry : Warehouse.groupsIndex.entrySet()) {\n            Log.d(TAG, \"Root映射表[ \" + stringClassEntry.getKey() + \" : \" + stringClassEntry.getValue() + \"]\");\n        }\n\n    }\n\n    public Postcard build(String path) {\n        if (TextUtils.isEmpty(path)) {\n            throw new RuntimeException(\"路由地址无效!\");\n        } else {\n            return build(path, extractGroup(path));\n        }\n    }\n\n    public Postcard build(String path, String group) {\n        if (TextUtils.isEmpty(path) || TextUtils.isEmpty(group)) {\n            throw new RuntimeException(\"路由地址无效!\");\n        } else {\n            return new Postcard(path, group);\n        }\n    }\n\n    /**\n     * 获得组别\n     *\n     * @param path\n     * @return\n     */\n    private String extractGroup(String path) {\n        if (TextUtils.isEmpty(path) || !path.startsWith(\"/\")) {\n            throw new RuntimeException(path + \" : 不能提取group.\");\n        }\n        try {\n            String defaultGroup = path.substring(1, path.indexOf(\"/\", 1));\n            if (TextUtils.isEmpty(defaultGroup)) {\n                throw new RuntimeException(path + \" : 不能提取group.\");\n            } else {\n                return defaultGroup;\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n            return null;\n        }\n    }\n\n    protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {\n\n        if (callback != null) {\n\n            InterceptorImpl.onInterceptions(postcard, new InterceptorCallback() {\n                @Override\n                public void onNext(Postcard postcard) {\n                    _navigation(context, postcard, requestCode, callback);\n                }\n\n                @Override\n                public void onInterrupt(String interruptMsg) {\n\n                    callback.onInterrupt(new Throwable(interruptMsg));\n                }\n            });\n        }else{\n\n            return _navigation(context, postcard, requestCode, callback);\n        }\n\n        return null;\n    }\n\n    protected Object _navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {\n        try {\n            prepareCard(postcard);\n        } catch (NoRouteFoundException e) {\n            e.printStackTrace();\n            //没找到\n            if (null != callback) {\n                callback.onLost(postcard);\n            }\n            return null;\n        }\n        if (null != callback) {\n            callback.onFound(postcard);\n        }\n\n        switch (postcard.getType()) {\n            case ACTIVITY:\n                final Context currentContext = null == context ? mContext : context;\n                final Intent intent = new Intent(currentContext, postcard.getDestination());\n                intent.putExtras(postcard.getExtras());\n                int flags = postcard.getFlags();\n                if (-1 != flags) {\n                    intent.setFlags(flags);\n                } else if (!(currentContext instanceof Activity)) {\n                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n                }\n                mHandler.post(new Runnable() {\n                    @Override\n                    public void run() {\n                        //可能需要返回码\n                        if (requestCode > 0) {\n                            ActivityCompat.startActivityForResult((Activity) currentContext, intent,\n                                    requestCode, postcard.getOptionsBundle());\n                        } else {\n                            ActivityCompat.startActivity(currentContext, intent, postcard\n                                    .getOptionsBundle());\n                        }\n\n                        if ((0 != postcard.getEnterAnim() || 0 != postcard.getExitAnim()) &&\n                                currentContext instanceof Activity) {\n                            //老版本\n                            ((Activity) currentContext).overridePendingTransition(postcard\n                                            .getEnterAnim()\n                                    , postcard.getExitAnim());\n                        }\n                        //跳转完成\n                        if (null != callback) {\n                            callback.onArrival(postcard);\n                        }\n                    }\n                });\n                break;\n            case ISERVICE:\n                return postcard.getService();\n            default:\n                break;\n        }\n        return null;\n    }\n\n    /**\n     * 准备卡片\n     *\n     * @param card\n     */\n    private void prepareCard(Postcard card) {\n        RouteMeta routeMeta = Warehouse.routes.get(card.getPath());\n        if (null == routeMeta) {\n            Class<? extends IRouteGroup> groupMeta = Warehouse.groupsIndex.get(card.getGroup());\n            if (null == groupMeta) {\n                throw new NoRouteFoundException(\"没找到对应路由：分组=\" + card.getGroup() + \"   路径=\" + card.getPath());\n            }\n            IRouteGroup iGroupInstance;\n            try {\n                iGroupInstance = groupMeta.getConstructor().newInstance();\n            } catch (Exception e) {\n                throw new RuntimeException(\"路由分组映射表记录失败.\", e);\n            }\n            iGroupInstance.loadInto(Warehouse.routes);\n            //已经准备过了就可以移除了 (不会一直存在内存中)\n            Warehouse.groupsIndex.remove(card.getGroup());\n            //再次进入 else\n            prepareCard(card);\n        } else {\n            //类 要跳转的activity 或IService实现类\n            card.setDestination(routeMeta.getDestination());\n            card.setType(routeMeta.getType());\n            switch (routeMeta.getType()) {\n                case ISERVICE:\n                    Class<?> destination = routeMeta.getDestination();\n                    IService service = Warehouse.services.get(destination);\n                    if (null == service) {\n                        try {\n                            service = (IService) destination.getConstructor().newInstance();\n                            Warehouse.services.put(destination, service);\n                        } catch (Exception e) {\n                            e.printStackTrace();\n                        }\n                    }\n                    card.setService(service);\n                    break;\n                default:\n                    break;\n            }\n        }\n    }\n\n    /**\n     * 注入\n     *\n     * @param instance\n     */\n    public void inject(Activity instance) {\n        ExtraManager.getInstance().loadExtras(instance);\n    }\n}\n"
  },
  {
    "path": "easy-core/src/main/java/com/xsm/easy/core/ExtraManager.java",
    "content": "package com.xsm.easy.core;\n\nimport android.app.Activity;\nimport android.util.LruCache;\n\nimport com.xsm.easy.core.template.IExtra;\n\n/**\n * Author: 夏胜明\n * Date: 2018/4/25 0025\n * Email: xiasem@163.com\n * Description:\n */\n\npublic class ExtraManager {\n    public static final String SUFFIX_AUTOWIRED = \"_Extra\";\n    private static ExtraManager instance;\n    private LruCache<String, IExtra> classCache;\n\n    public static ExtraManager getInstance() {\n        if (instance == null) {\n            synchronized (ExtraManager.class) {\n                if (instance == null) {\n                    instance = new ExtraManager();\n                }\n            }\n        }\n        return instance;\n    }\n\n\n    public ExtraManager() {\n        classCache = new LruCache<>(66);\n    }\n\n\n    /**\n     * 注入\n     *\n     * @param instance\n     */\n    public void loadExtras(Activity instance) {\n        //查找对应activity的缓存\n        String className = instance.getClass().getName();\n        IExtra iExtra = classCache.get(className);\n        try {\n            if (null == iExtra) {\n                iExtra = (IExtra) Class.forName(instance.getClass().getName() +\n                        SUFFIX_AUTOWIRED).getConstructor().newInstance();\n            }\n            iExtra.loadExtra(instance);\n            classCache.put(className, iExtra);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n}\n"
  },
  {
    "path": "easy-core/src/main/java/com/xsm/easy/core/Postcard.java",
    "content": "package com.xsm.easy.core;\n\nimport android.content.Context;\nimport android.os.Bundle;\nimport android.os.Parcelable;\nimport android.support.annotation.Nullable;\nimport android.support.v4.app.ActivityOptionsCompat;\n\nimport com.xsm.easy.annotation.modle.RouteMeta;\nimport com.xsm.easy.core.callback.NavigationCallback;\nimport com.xsm.easy.core.template.IService;\n\nimport java.util.ArrayList;\n\n/**\n * Author: 夏胜明\n * Date: 2018/4/24 0024\n * Email: xiasem@163.com\n * Description:\n */\n\npublic class Postcard extends RouteMeta {\n    private Bundle mBundle;\n    private int flags = -1;\n    //新版风格\n    private Bundle optionsCompat;\n    //老版\n    private int enterAnim;\n    private int exitAnim;\n\n    //服务\n    private IService service;\n\n    public Postcard(String path, String group) {\n        this(path, group, null);\n    }\n\n    public Postcard(String path, String group, Bundle bundle) {\n        setPath(path);\n        setGroup(group);\n        this.mBundle = (null == bundle ? new Bundle() : bundle);\n    }\n\n    public Bundle getExtras() {return mBundle;}\n\n    public int getEnterAnim() {return enterAnim;}\n\n    public int getExitAnim() {return exitAnim;}\n\n    public IService getService() {\n        return service;\n    }\n\n    public void setService(IService service) {\n        this.service = service;\n    }\n\n    /**\n     * Intent.FLAG_ACTIVITY**\n     * @param flag\n     * @return\n     */\n    public Postcard withFlags(int flag) {\n        this.flags = flag;\n        return this;\n    }\n\n    public int getFlags() {\n        return flags;\n    }\n\n    /**\n     * 跳转动画\n     *\n     * @param enterAnim\n     * @param exitAnim\n     * @return\n     */\n    public Postcard withTransition(int enterAnim, int exitAnim) {\n        this.enterAnim = enterAnim;\n        this.exitAnim = exitAnim;\n        return this;\n    }\n\n    /**\n     * 转场动画\n     *\n     * @param compat\n     * @return\n     */\n    public Postcard withOptionsCompat(ActivityOptionsCompat compat) {\n        if (null != compat) {\n            this.optionsCompat = compat.toBundle();\n        }\n        return this;\n    }\n\n    public Postcard withString(@Nullable String key, @Nullable String value) {\n        mBundle.putString(key, value);\n        return this;\n    }\n\n\n    public Postcard withBoolean(@Nullable String key, boolean value) {\n        mBundle.putBoolean(key, value);\n        return this;\n    }\n\n\n    public Postcard withShort(@Nullable String key, short value) {\n        mBundle.putShort(key, value);\n        return this;\n    }\n\n\n    public Postcard withInt(@Nullable String key, int value) {\n        mBundle.putInt(key, value);\n        return this;\n    }\n\n\n    public Postcard withLong(@Nullable String key, long value) {\n        mBundle.putLong(key, value);\n        return this;\n    }\n\n\n    public Postcard withDouble(@Nullable String key, double value) {\n        mBundle.putDouble(key, value);\n        return this;\n    }\n\n\n    public Postcard withByte(@Nullable String key, byte value) {\n        mBundle.putByte(key, value);\n        return this;\n    }\n\n\n    public Postcard withChar(@Nullable String key, char value) {\n        mBundle.putChar(key, value);\n        return this;\n    }\n\n\n    public Postcard withFloat(@Nullable String key, float value) {\n        mBundle.putFloat(key, value);\n        return this;\n    }\n\n\n    public Postcard withParcelable(@Nullable String key, @Nullable Parcelable value) {\n        mBundle.putParcelable(key, value);\n        return this;\n    }\n\n\n    public Postcard withStringArray(@Nullable String key, @Nullable String[] value) {\n        mBundle.putStringArray(key, value);\n        return this;\n    }\n\n\n    public Postcard withBooleanArray(@Nullable String key, boolean[] value) {\n        mBundle.putBooleanArray(key, value);\n        return this;\n    }\n\n\n    public Postcard withShortArray(@Nullable String key, short[] value) {\n        mBundle.putShortArray(key, value);\n        return this;\n    }\n\n\n    public Postcard withIntArray(@Nullable String key, int[] value) {\n        mBundle.putIntArray(key, value);\n        return this;\n    }\n\n\n    public Postcard withLongArray(@Nullable String key, long[] value) {\n        mBundle.putLongArray(key, value);\n        return this;\n    }\n\n\n    public Postcard withDoubleArray(@Nullable String key, double[] value) {\n        mBundle.putDoubleArray(key, value);\n        return this;\n    }\n\n\n    public Postcard withByteArray(@Nullable String key, byte[] value) {\n        mBundle.putByteArray(key, value);\n        return this;\n    }\n\n\n    public Postcard withCharArray(@Nullable String key, char[] value) {\n        mBundle.putCharArray(key, value);\n        return this;\n    }\n\n\n    public Postcard withFloatArray(@Nullable String key, float[] value) {\n        mBundle.putFloatArray(key, value);\n        return this;\n    }\n\n\n    public Postcard withParcelableArray(@Nullable String key, @Nullable Parcelable[] value) {\n        mBundle.putParcelableArray(key, value);\n        return this;\n    }\n\n    public Postcard withParcelableArrayList(@Nullable String key, @Nullable ArrayList<? extends\n            Parcelable> value) {\n        mBundle.putParcelableArrayList(key, value);\n        return this;\n    }\n\n    public Postcard withIntegerArrayList(@Nullable String key, @Nullable ArrayList<Integer> value) {\n        mBundle.putIntegerArrayList(key, value);\n        return this;\n    }\n\n    public Postcard withStringArrayList(@Nullable String key, @Nullable ArrayList<String> value) {\n        mBundle.putStringArrayList(key, value);\n        return this;\n    }\n\n    public Bundle getOptionsBundle() {\n        return optionsCompat;\n    }\n\n    public Object navigation() {\n        return EasyRouter.getsInstance().navigation(null, this, -1, null);\n    }\n\n    public Object navigation(Context context) {\n        return EasyRouter.getsInstance().navigation(context, this, -1, null);\n    }\n\n\n    public Object navigation(Context context, NavigationCallback callback) {\n        return EasyRouter.getsInstance().navigation(context, this, -1, callback);\n    }\n\n    public Object navigation(Context context, int requestCode) {\n        return EasyRouter.getsInstance().navigation(context, this, requestCode, null);\n    }\n\n    public Object navigation(Context context, int requestCode, NavigationCallback callback) {\n        return EasyRouter.getsInstance().navigation(context, this, requestCode, callback);\n    }\n\n\n}\n"
  },
  {
    "path": "easy-core/src/main/java/com/xsm/easy/core/Warehouse.java",
    "content": "package com.xsm.easy.core;\n\nimport com.xsm.easy.annotation.modle.RouteMeta;\nimport com.xsm.easy.core.template.IInterceptor;\nimport com.xsm.easy.core.template.IRouteGroup;\nimport com.xsm.easy.core.template.IService;\nimport com.xsm.easy.core.utils.UniqueKeyTreeMap;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * Author: 夏胜明\n * Date: 2018/4/24 0024\n * Email: xiasem@163.com\n * Description:\n */\n\npublic class Warehouse {\n\n    // root 映射表 保存分组信息\n    static Map<String, Class<? extends IRouteGroup>> groupsIndex = new HashMap<>();\n\n    // group 映射表 保存组中的所有数据\n    static Map<String, RouteMeta> routes = new HashMap<>();\n\n    // group 映射表 保存组中的所有数据\n    static Map<Class, IService> services = new HashMap<>();\n    // TestServiceImpl.class , TestServiceImpl 没有再反射\n\n    /**\n     * 以键值对优先级的方式保存拦截器对象\n     */\n    public static Map<Integer, Class<? extends IInterceptor>> interceptorsIndex = new UniqueKeyTreeMap<>();\n    /**\n     * 以集合的方式保存所有拦截器对象\n     */\n    public static List<IInterceptor> interceptors = new ArrayList<>();\n}\n"
  },
  {
    "path": "easy-core/src/main/java/com/xsm/easy/core/callback/InterceptorCallback.java",
    "content": "package com.xsm.easy.core.callback;\n\nimport com.xsm.easy.core.Postcard;\n\n/**\n * @author: luoxiaohui\n * @date: 2019-05-23 20:41\n * @desc: 拦截器回调\n */\npublic interface InterceptorCallback {\n\n    /**\n     * 未拦截，走正常流程\n     * @author luoxiaohui\n     * @createTime 2019-05-23 20:50\n     */\n    void onNext(Postcard postcard);\n\n    /**\n     * 拦截器拦截成功，中断流程\n     * @author luoxiaohui\n     * @createTime 2019-05-23 20:42\n     */\n    void onInterrupt(String interruptMsg);\n}\n"
  },
  {
    "path": "easy-core/src/main/java/com/xsm/easy/core/callback/NavigationCallback.java",
    "content": "package com.xsm.easy.core.callback;\n\nimport com.xsm.easy.core.Postcard;\n\n/**\n * Author: 夏胜明\n * Date: 2018/4/25 0025\n * Email: xiasem@163.com\n * Description:\n */\n\npublic interface NavigationCallback {\n\n    /**\n     * 找到跳转页面\n     * @param postcard\n     */\n    void onFound(Postcard postcard);\n\n    /**\n     * 未找到\n     * @param postcard\n     */\n    void onLost(Postcard postcard);\n\n    /**\n     * 成功跳转\n     * @param postcard\n     */\n    void onArrival(Postcard postcard);\n\n    /**\n     * 中断了路由跳转\n     * @author luoxiaohui\n     * @createTime 2019-06-18 17:00\n     */\n    void onInterrupt(Throwable throwable);\n}\n"
  },
  {
    "path": "easy-core/src/main/java/com/xsm/easy/core/exception/NoRouteFoundException.java",
    "content": "package com.xsm.easy.core.exception;\n\n/**\n * Author: 夏胜明\n * Date: 2018/4/25 0025\n * Email: xiasem@163.com\n * Description:\n */\n\npublic class NoRouteFoundException extends RuntimeException {\n\n    public NoRouteFoundException(String detailMessage) {\n        super(detailMessage);\n    }\n}\n"
  },
  {
    "path": "easy-core/src/main/java/com/xsm/easy/core/implments/InterceptorImpl.java",
    "content": "package com.xsm.easy.core.implments;\n\nimport android.content.Context;\n\nimport com.xsm.easy.core.Postcard;\nimport com.xsm.easy.core.Warehouse;\nimport com.xsm.easy.core.callback.InterceptorCallback;\nimport com.xsm.easy.core.template.IInterceptor;\nimport com.xsm.easy.core.thread.DefaultPoolExecutor;\nimport com.xsm.easy.core.utils.CancelableCountDownLatch;\nimport com.xsm.easy.core.utils.Utils;\n\nimport java.lang.reflect.InvocationTargetException;\nimport java.util.Map;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * @author: luoxiaohui\n * @date: 2019-06-18 14:08\n * @desc: 拦截器实现，在初始化路由，以及调用路由时，都需要调用到此类\n */\npublic class InterceptorImpl {\n\n    /**\n     * 初始化路由时，需要轮询每个拦截器中的init()方法\n     *\n     * @author luoxiaohui\n     * @createTime 2019-06-18 14:10\n     */\n    public static void init(final Context context) {\n\n        DefaultPoolExecutor.executor.execute(new Runnable() {\n            @Override\n            public void run() {\n                if (!Utils.isEmpty(Warehouse.interceptorsIndex)) {\n                    for (Map.Entry<Integer, Class<? extends IInterceptor>> entry : Warehouse.interceptorsIndex.entrySet()) {\n                        Class<? extends IInterceptor> interceptorClass = entry.getValue();\n                        try {\n                            IInterceptor iInterceptor = interceptorClass.getConstructor().newInstance();\n                            iInterceptor.init(context);\n                            Warehouse.interceptors.add(iInterceptor);\n                        } catch (Exception e) {\n                            e.printStackTrace();\n                        }\n                    }\n                }\n            }\n        });\n    }\n\n    /**\n     * 执行拦截逻辑\n     *\n     * @author luoxiaohui\n     * @createTime 2019-06-18 14:56\n     */\n    public static void onInterceptions(final Postcard postcard, final InterceptorCallback callback) {\n\n        if (Warehouse.interceptors.size() > 0) {\n            DefaultPoolExecutor.executor.execute(new Runnable() {\n                @Override\n                public void run() {\n\n                    CancelableCountDownLatch countDownLatch = new CancelableCountDownLatch(Warehouse.interceptors.size());\n                    execute(0, countDownLatch, postcard);\n                    try {\n                        countDownLatch.await(300, TimeUnit.SECONDS);\n                        if (countDownLatch.getCount() > 0){\n\n                            callback.onInterrupt(\"拦截器处理超时\");\n                        }else if(!Utils.isEmpty(countDownLatch.getMsg())){\n\n                            callback.onInterrupt(countDownLatch.getMsg());\n                        }else {\n\n                            callback.onNext(postcard);\n                        }\n                    } catch (InterruptedException e) {\n                        e.printStackTrace();\n                    }\n                }\n            });\n        } else {\n\n            callback.onNext(postcard);\n        }\n    }\n\n\n    /**\n     * 以递归的方式走完所有拦截器的process()方法\n     *\n     * @author luoxiaohui\n     * @createTime 2019-06-18 15:22\n     */\n    private static void execute(final int index, final CancelableCountDownLatch countDownLatch, final Postcard postcard) {\n        if (index < Warehouse.interceptors.size()){\n\n            IInterceptor iInterceptor = Warehouse.interceptors.get(index);\n            iInterceptor.process(postcard, new InterceptorCallback() {\n                @Override\n                public void onNext(Postcard postcard) {\n\n                    countDownLatch.countDown();\n                    execute(index + 1, countDownLatch, postcard);\n                }\n\n                @Override\n                public void onInterrupt(String msg) {\n\n                    countDownLatch.cancel(msg);\n                }\n            });\n        }\n    }\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "easy-core/src/main/java/com/xsm/easy/core/template/IExtra.java",
    "content": "package com.xsm.easy.core.template;\n\n/**\n * 注入\n */\npublic interface IExtra {\n    void loadExtra(Object target);\n}\n"
  },
  {
    "path": "easy-core/src/main/java/com/xsm/easy/core/template/IInterceptor.java",
    "content": "package com.xsm.easy.core.template;\n\nimport android.content.Context;\n\nimport com.xsm.easy.core.Postcard;\nimport com.xsm.easy.core.callback.InterceptorCallback;\n\n/**\n * @author: luoxiaohui\n * @date: 2019-05-23 20:52\n * @desc:\n */\npublic interface IInterceptor {\n    \n    /**\n     * 拦截器流程\n     * @author luoxiaohui\n     * @createTime 2019-05-23 20:53\n     */\n    void process(Postcard postcard, InterceptorCallback callback);\n\n    /**\n     * 在调用EasyRouter.init()初始化时，会调用到此方法\n     * @author luoxiaohui\n     * @createTime 2019-06-18 10:39\n     */\n    void init(Context context);\n}\n"
  },
  {
    "path": "easy-core/src/main/java/com/xsm/easy/core/template/IInterceptorGroup.java",
    "content": "package com.xsm.easy.core.template;\n\nimport java.util.Map;\n\n/**\n * @author: luoxiaohui\n * @date: 2019-05-23 20:36\n * @desc:\n */\npublic interface IInterceptorGroup {\n\n    /**\n     * key为拦截器的优先级，value为拦截器\n     * @author luoxiaohui\n     * @createTime 2019-05-23 20:54\n     * @param map\n     */\n    void loadInto(Map<Integer, Class<? extends IInterceptor>> map);\n}\n"
  },
  {
    "path": "easy-core/src/main/java/com/xsm/easy/core/template/IRouteGroup.java",
    "content": "package com.xsm.easy.core.template;\n\nimport com.xsm.easy.annotation.modle.RouteMeta;\n\nimport java.util.Map;\n\n/**\n * Author: 夏胜明\n * Date: 2018/3/29 0029\n * Email: xiasem@163.com\n * Description:\n */\n\npublic interface IRouteGroup {\n    void loadInto(Map<String, RouteMeta> atlas);\n}\n"
  },
  {
    "path": "easy-core/src/main/java/com/xsm/easy/core/template/IRouteRoot.java",
    "content": "package com.xsm.easy.core.template;\n\nimport java.util.Map;\n\n/**\n * Author: 夏胜明\n * Date: 2018/3/29 0029\n * Email: xiasem@163.com\n * Description:\n */\n\npublic interface IRouteRoot {\n    void loadInto(Map<String, Class<? extends IRouteGroup>> routes);\n}\n"
  },
  {
    "path": "easy-core/src/main/java/com/xsm/easy/core/template/IService.java",
    "content": "package com.xsm.easy.core.template;\n\n/**\n * Author: 夏胜明\n * Date: 2018/3/29 0029\n * Email: xiasem@163.com\n * Description: 用于组件之间业务通信\n */\n\npublic interface IService {\n}\n"
  },
  {
    "path": "easy-core/src/main/java/com/xsm/easy/core/thread/DefaultPoolExecutor.java",
    "content": "package com.xsm.easy.core.thread;\n\nimport java.util.concurrent.ArrayBlockingQueue;\nimport java.util.concurrent.ThreadFactory;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicInteger;\n\n/**\n * Author: 夏胜明\n * Date: 2018/4/3 0003\n * Email: xiasem@163.com\n * Description:\n */\n\npublic class DefaultPoolExecutor {\n\n    public static ThreadPoolExecutor executor;\n    private static final ThreadFactory sThreadFactory = new ThreadFactory() {\n        private final AtomicInteger mCount = new AtomicInteger(1);\n\n        @Override\n        public Thread newThread(Runnable r) {\n            return new Thread(r, \"EasyRouter #\" + mCount.getAndIncrement());\n        }\n    };\n\n    //核心线程和最大线程都是cpu核心数+1\n    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();\n    private static final int MAX_CORE_POOL_SIZE = CPU_COUNT + 1;\n    //存活30秒 回收线程\n    private static final long SURPLUS_THREAD_LIFE = 30L;\n\n    public static ThreadPoolExecutor newDefaultPoolExecutor(int corePoolSize) {\n        if (corePoolSize == 0) {\n            return null;\n        }\n        corePoolSize = Math.min(corePoolSize, MAX_CORE_POOL_SIZE);\n        executor = new ThreadPoolExecutor(corePoolSize,\n                corePoolSize, SURPLUS_THREAD_LIFE, TimeUnit.SECONDS, new\n                ArrayBlockingQueue<Runnable>(64), sThreadFactory);\n        //核心线程也会被销毁\n        executor.allowCoreThreadTimeOut(true);\n        return executor;\n    }\n\n\n\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "easy-core/src/main/java/com/xsm/easy/core/utils/CancelableCountDownLatch.java",
    "content": "package com.xsm.easy.core.utils;\n\nimport java.util.concurrent.CountDownLatch;\n\n/**\n * @author: luoxiaohui\n * @date: 2019-06-18 14:46\n * @desc:\n */\npublic class CancelableCountDownLatch extends CountDownLatch {\n\n    private String msg = \"\";\n\n    public CancelableCountDownLatch(int count) {\n        super(count);\n    }\n\n    /**\n     * 当遇到特殊情况时，需要将计步器清0\n     *\n     * @author luoxiaohui\n     * @createTime 2019-06-18 14:47\n     */\n    public void cancel(String msg) {\n        this.msg = msg;\n        while (getCount() > 0) {\n            countDown();\n        }\n    }\n\n    public String getMsg(){\n        return msg;\n    }\n}\n"
  },
  {
    "path": "easy-core/src/main/java/com/xsm/easy/core/utils/ClassUtils.java",
    "content": "package com.xsm.easy.core.utils;\n\nimport android.app.Application;\nimport android.content.Context;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageManager;\nimport android.os.Build;\nimport android.text.TextUtils;\n\nimport com.xsm.easy.core.thread.DefaultPoolExecutor;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Enumeration;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ThreadPoolExecutor;\n\nimport dalvik.system.DexFile;\n\n/**\n * Author: 夏胜明\n * Date: 2018/4/3 0003\n * Email: xiasem@163.com\n * Description:\n */\n\npublic class ClassUtils {\n\n    /**\n     * 获得程序所有的apk(instant run会产生很多split apk)\n     * @param context\n     * @return\n     * @throws PackageManager.NameNotFoundException\n     */\n    private static List<String> getSourcePaths(Context context) throws PackageManager.NameNotFoundException {\n        ApplicationInfo applicationInfo = context.getPackageManager().getApplicationInfo(context.getPackageName(), 0);\n        List<String> sourcePaths = new ArrayList<>();\n        sourcePaths.add(applicationInfo.sourceDir);\n        //instant run\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {\n            if (null != applicationInfo.splitSourceDirs) {\n                sourcePaths.addAll(Arrays.asList(applicationInfo.splitSourceDirs));\n            }\n        }\n        return sourcePaths;\n    }\n\n    /**\n     * 得到路由表的类名\n     * @param context\n     * @param packageName\n     * @return\n     * @throws PackageManager.NameNotFoundException\n     * @throws InterruptedException\n     */\n    public static Set<String> getFileNameByPackageName(Application context, final String packageName)\n            throws PackageManager.NameNotFoundException, InterruptedException {\n        final Set<String> classNames = new HashSet<>();\n        List<String> paths = getSourcePaths(context);\n        //使用同步计数器判断均处理完成\n        final CountDownLatch countDownLatch = new CountDownLatch(paths.size());\n        ThreadPoolExecutor threadPoolExecutor = DefaultPoolExecutor.newDefaultPoolExecutor(paths.size());\n        for (final String path : paths) {\n            threadPoolExecutor.execute(new Runnable() {\n                @Override\n                public void run() {\n                    DexFile dexFile = null;\n                    try {\n                        //加载 apk中的dex 并遍历 获得所有包名为 {packageName} 的类\n                        dexFile = new DexFile(path);\n                        Enumeration<String> dexEntries = dexFile.entries();\n                        while (dexEntries.hasMoreElements()) {\n                            String className = dexEntries.nextElement();\n                            if (!TextUtils.isEmpty(className) && className.startsWith(packageName)) {\n                                classNames.add(className);\n                            }\n                        }\n                    } catch (IOException e) {\n                        e.printStackTrace();\n                    } finally {\n                        if (null != dexFile) {\n                            try {\n                                dexFile.close();\n                            } catch (IOException e) {\n                                e.printStackTrace();\n                            }\n                        }\n                        //释放一个\n                        countDownLatch.countDown();\n                    }\n                }\n            });\n        }\n        //等待执行完成\n        countDownLatch.await();\n        return classNames;\n    }\n\n\n}\n"
  },
  {
    "path": "easy-core/src/main/java/com/xsm/easy/core/utils/UniqueKeyTreeMap.java",
    "content": "package com.xsm.easy.core.utils;\n\nimport java.util.TreeMap;\n\n/**\n * @author: luoxiaohui\n * @date: 2019-06-17 15:38\n * @desc: 主要用于拦截器优先级\n */\npublic class UniqueKeyTreeMap<K, V> extends TreeMap<K, V> {\n\n    @Override\n    public V put(K key, V value) {\n        if (containsKey(key)){\n\n            throw new RuntimeException(\"优先级为\" + key + \"的拦截器已经存在，不允许再次添加同级别的拦截器！\");\n        }else{\n\n            return super.put(key, value);\n        }\n    }\n}\n"
  },
  {
    "path": "easy-core/src/main/java/com/xsm/easy/core/utils/Utils.java",
    "content": "package com.xsm.easy.core.utils;\n\nimport java.util.Collection;\nimport java.util.Map;\n\n/**\n * @author: luoxiaohui\n * @date: 2019-06-18 14:21\n * @desc: 判断集合，Map等是否为空\n */\npublic class Utils {\n\n    public static boolean isEmpty(String str){\n        return str == null || str.equals(\"\") || str.isEmpty();\n    }\n\n    public static boolean isEmpty(Collection<?> coll) {\n        return coll == null || coll.isEmpty();\n    }\n\n    public static boolean isEmpty(final Map<?, ?> map) {\n        return map == null || map.isEmpty();\n    }\n}\n"
  },
  {
    "path": "easy-core/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">easy-core</string>\n</resources>\n"
  },
  {
    "path": "easy-core/src/test/java/com/xsm/easy/core/ExampleUnitTest.java",
    "content": "package com.xsm.easy.core;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.*;\n\n/**\n * Example local unit test, which will execute on the development machine (host).\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\npublic class ExampleUnitTest {\n    @Test\n    public void addition_isCorrect() throws Exception {\n        assertEquals(4, 2 + 2);\n    }\n}"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "#Tue Mar 27 09:07:20 CST 2018\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-5.1.1-all.zip\n"
  },
  {
    "path": "gradle.properties",
    "content": "# Project-wide Gradle settings.\n\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\norg.gradle.jvmargs=-Xmx1536m\n\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true\n"
  },
  {
    "path": "gradlew",
    "content": "#!/usr/bin/env bash\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS=\"\"\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn ( ) {\n    echo \"$*\"\n}\n\ndie ( ) {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\nesac\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules\nfunction splitJvmOpts() {\n    JVM_OPTS=(\"$@\")\n}\neval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS\nJVM_OPTS[${#JVM_OPTS[*]}]=\"-Dorg.gradle.appname=$APP_BASE_NAME\"\n\nexec \"$JAVACMD\" \"${JVM_OPTS[@]}\" -classpath \"$CLASSPATH\" org.gradle.wrapper.GradleWrapperMain \"$@\"\n"
  },
  {
    "path": "gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem  Gradle startup script for Windows\n@rem\n@rem ##########################################################################\n\n@rem Set local scope for the variables with windows NT shell\nif \"%OS%\"==\"Windows_NT\" setlocal\n\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nset DEFAULT_JVM_OPTS=\n\nset DIRNAME=%~dp0\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\nset APP_BASE_NAME=%~n0\nset APP_HOME=%DIRNAME%\n\n@rem Find java.exe\nif defined JAVA_HOME goto findJavaFromJavaHome\n\nset JAVA_EXE=java.exe\n%JAVA_EXE% -version >NUL 2>&1\nif \"%ERRORLEVEL%\" == \"0\" goto init\n\necho.\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:findJavaFromJavaHome\nset JAVA_HOME=%JAVA_HOME:\"=%\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\n\nif exist \"%JAVA_EXE%\" goto init\n\necho.\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:init\n@rem Get command-line arguments, handling Windowz variants\n\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\nif \"%@eval[2+2]\" == \"4\" goto 4NT_args\n\n:win9xME_args\n@rem Slurp the command line arguments.\nset CMD_LINE_ARGS=\nset _SKIP=2\n\n:win9xME_args_slurp\nif \"x%~1\" == \"x\" goto execute\n\nset CMD_LINE_ARGS=%*\ngoto execute\n\n:4NT_args\n@rem Get arguments from the 4NT Shell from JP Software\nset CMD_LINE_ARGS=%$\n\n:execute\n@rem Setup the command line\n\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\n\n@rem Execute Gradle\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\n\n:end\n@rem End local scope for the variables with windows NT shell\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\n\n:fail\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\nrem the _cmd.exe /c_ return code!\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\nexit /b 1\n\n:mainEnd\nif \"%OS%\"==\"Windows_NT\" endlocal\n\n:omega\n"
  },
  {
    "path": "module1/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "module1/build.gradle",
    "content": "if (isModule) {\n    apply plugin: 'com.android.library'\n} else {\n    apply plugin: 'com.android.application'\n}\n\ndef cfg = rootProject.ext.android\ndef appId = rootProject.ext.appId\n\nandroid {\n    compileSdkVersion cfg.compileSdkVersion\n\n    defaultConfig {\n        if (!isModule) {\n            applicationId appId.module1\n        }\n        minSdkVersion cfg.minSdkVersion\n        targetSdkVersion cfg.targetSdkVersion\n        versionCode cfg.versionCode\n        versionName cfg.versionName\n        testInstrumentationRunner \"android.support.test.runner.AndroidJUnitRunner\"\n        javaCompileOptions {\n            annotationProcessorOptions {\n                arguments = [moduleName: project.getName()]\n            }\n        }\n\n        //添加一条 boolean类型的变量\n        buildConfigField(\"boolean\", \"isModule\", String.valueOf(isModule))\n\n        sourceSets {\n            main {\n                if (isModule) {\n                    manifest.srcFile 'src/main/AndroidManifest.xml'\n                } else {\n                    manifest.srcFile 'src/main/module/AndroidManifest.xml'\n                    java.srcDirs 'src/main/module/java', 'src/main/java'\n                }\n            }\n        }\n    }\n\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n\n}\n\ndependencies {\n    implementation fileTree(dir: 'libs', include: ['*.jar'])\n    implementation 'com.android.support.constraint:constraint-layout:1.0.2'\n    testImplementation 'junit:junit:4.12'\n    androidTestImplementation 'com.android.support.test:runner:1.0.1'\n    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'\n\n    annotationProcessor project(':easy-compiler')\n    implementation project(':base')\n}\n"
  },
  {
    "path": "module1/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "module1/src/androidTest/java/com/xsm/module1/ExampleInstrumentedTest.java",
    "content": "package com.xsm.module1;\n\nimport android.content.Context;\nimport android.support.test.InstrumentationRegistry;\nimport android.support.test.runner.AndroidJUnit4;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\nimport static org.junit.Assert.*;\n\n/**\n * Instrumented test, which will execute on an Android device.\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\n@RunWith(AndroidJUnit4.class)\npublic class ExampleInstrumentedTest {\n    @Test\n    public void useAppContext() throws Exception {\n        // Context of the app under test.\n        Context appContext = InstrumentationRegistry.getTargetContext();\n\n        assertEquals(\"com.xsm.module1\", appContext.getPackageName());\n    }\n}\n"
  },
  {
    "path": "module1/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n          package=\"com.xsm.module1\">\n\n    <application>\n        <activity android:name=\".Module1MainActivity\"/>\n    </application>\n\n</manifest>\n"
  },
  {
    "path": "module1/src/main/java/com/xsm/module1/LoginInterceptor.java",
    "content": "package com.xsm.module1;\n\nimport android.content.Context;\nimport android.util.Log;\n\nimport com.xsm.easy.annotation.Interceptor;\nimport com.xsm.easy.core.Postcard;\nimport com.xsm.easy.core.callback.InterceptorCallback;\nimport com.xsm.easy.core.template.IInterceptor;\n\n/**\n * @author: luoxiaohui\n * @date: 2019-05-30 20:35\n * @desc:\n */\n@Interceptor(priority = 1, name = \"login\")\npublic class LoginInterceptor implements IInterceptor {\n\n    private static final String TAG = \"LoginInterceptor\";\n\n    /**\n     * 拦截器流程\n     *\n     * @param postcard\n     * @param callback\n     * @author luoxiaohui\n     * @createTime 2019-05-23 20:53\n     */\n    @Override\n    public void process(Postcard postcard, InterceptorCallback callback) {\n\n        Log.e(TAG, \"process()...\");\n        callback.onNext(postcard);\n    }\n\n    /**\n     * 在调用EasyRouter.init()初始化时，会调用到此方法\n     *\n     * @param context\n     * @author luoxiaohui\n     * @createTime 2019-06-18 10:39\n     */\n    @Override\n    public void init(Context context) {\n\n        Log.e(TAG, \"init()...\");\n    }\n}\n"
  },
  {
    "path": "module1/src/main/java/com/xsm/module1/Module1MainActivity.java",
    "content": "package com.xsm.module1;\n\nimport android.support.v7.app.AppCompatActivity;\nimport android.os.Bundle;\nimport android.widget.Toast;\n\nimport com.xsm.easy.annotation.Extra;\nimport com.xsm.easy.annotation.Route;\nimport com.xsm.easy.core.EasyRouter;\n\n@Route(path = \"/module1/module1main\")\npublic class Module1MainActivity extends AppCompatActivity {\n\n    @Extra\n    String msg;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_module1_main);\n        EasyRouter.getsInstance().inject(this);\n        Toast.makeText(this, \"msg=\" + msg, Toast.LENGTH_SHORT).show();\n\n    }\n}\n"
  },
  {
    "path": "module1/src/main/java/com/xsm/module1/Module1ProvidersImpl.java",
    "content": "package com.xsm.module1;\n\nimport com.xsm.base.providers.module1.Module1Providers;\nimport com.xsm.easy.annotation.Route;\n\n/**\n * Author: 夏胜明\n * Date: 2018/8/20 0020\n * Email: xiasem@163.com\n * Description:\n */\n@Route(path = \"/module1/providers\")\npublic class Module1ProvidersImpl implements Module1Providers {\n\n    @Override\n    public int add(int a, int b) {\n        return a + b;\n    }\n\n}\n"
  },
  {
    "path": "module1/src/main/module/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n          package=\"com.xsm.module1\">\n\n    <application\n        android:allowBackup=\"true\"\n        android:icon=\"@mipmap/ic_launcher\"\n        android:label=\"@string/app_name\"\n        android:roundIcon=\"@mipmap/ic_launcher_round\"\n        android:supportsRtl=\"true\"\n        android:theme=\"@style/AppTheme\">\n        <activity android:name=\".Module1MainActivity\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity>\n    </application>\n\n</manifest>"
  },
  {
    "path": "module1/src/main/res/drawable/ic_launcher_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportHeight=\"108\"\n    android:viewportWidth=\"108\">\n    <path\n        android:fillColor=\"#26A69A\"\n        android:pathData=\"M0,0h108v108h-108z\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M9,0L9,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,0L19,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M29,0L29,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M39,0L39,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M49,0L49,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M59,0L59,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M69,0L69,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M79,0L79,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M89,0L89,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M99,0L99,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,9L108,9\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,19L108,19\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,29L108,29\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,39L108,39\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,49L108,49\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,59L108,59\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,69L108,69\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,79L108,79\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,89L108,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,99L108,99\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,29L89,29\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,39L89,39\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,49L89,49\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,59L89,59\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,69L89,69\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,79L89,79\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M29,19L29,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M39,19L39,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M49,19L49,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M59,19L59,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M69,19L69,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M79,19L79,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n</vector>\n"
  },
  {
    "path": "module1/src/main/res/drawable-v24/ic_launcher_foreground.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        xmlns:aapt=\"http://schemas.android.com/aapt\"\n        android:width=\"108dp\"\n        android:height=\"108dp\"\n        android:viewportHeight=\"108\"\n        android:viewportWidth=\"108\">\n    <path\n        android:fillType=\"evenOdd\"\n        android:pathData=\"M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z\"\n        android:strokeColor=\"#00000000\"\n        android:strokeWidth=\"1\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                android:endX=\"78.5885\"\n                android:endY=\"90.9159\"\n                android:startX=\"48.7653\"\n                android:startY=\"61.0927\"\n                android:type=\"linear\">\n                <item\n                    android:color=\"#44000000\"\n                    android:offset=\"0.0\"/>\n                <item\n                    android:color=\"#00000000\"\n                    android:offset=\"1.0\"/>\n            </gradient>\n        </aapt:attr>\n    </path>\n    <path\n        android:fillColor=\"#FFFFFF\"\n        android:fillType=\"nonZero\"\n        android:pathData=\"M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z\"\n        android:strokeColor=\"#00000000\"\n        android:strokeWidth=\"1\"/>\n</vector>\n"
  },
  {
    "path": "module1/src/main/res/layout/activity_module1_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    tools:context=\"com.xsm.module1.Module1MainActivity\">\n\n    <TextView\n        android:text=\"Module1\"\n        android:layout_gravity=\"center_horizontal\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"/>\n\n</LinearLayout>\n"
  },
  {
    "path": "module1/src/main/res/mipmap-anydpi-v26/ic_launcher.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/ic_launcher_background\"/>\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\"/>\n</adaptive-icon>"
  },
  {
    "path": "module1/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/ic_launcher_background\"/>\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\"/>\n</adaptive-icon>"
  },
  {
    "path": "module1/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"colorPrimary\">#3F51B5</color>\n    <color name=\"colorPrimaryDark\">#303F9F</color>\n    <color name=\"colorAccent\">#FF4081</color>\n</resources>\n"
  },
  {
    "path": "module1/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">Module1</string>\n</resources>\n"
  },
  {
    "path": "module1/src/main/res/values/styles.xml",
    "content": "<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.DarkActionBar\">\n        <!-- Customize your theme here. -->\n        <item name=\"colorPrimary\">@color/colorPrimary</item>\n        <item name=\"colorPrimaryDark\">@color/colorPrimaryDark</item>\n        <item name=\"colorAccent\">@color/colorAccent</item>\n    </style>\n\n</resources>\n"
  },
  {
    "path": "module1/src/test/java/com/xsm/module1/ExampleUnitTest.java",
    "content": "package com.xsm.module1;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.*;\n\n/**\n * Example local unit test, which will execute on the development machine (host).\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\npublic class ExampleUnitTest {\n    @Test\n    public void addition_isCorrect() throws Exception {\n        assertEquals(4, 2 + 2);\n    }\n}"
  },
  {
    "path": "module2/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "module2/build.gradle",
    "content": "if (isModule) {\n    apply plugin: 'com.android.library'\n} else {\n    apply plugin: 'com.android.application'\n}\n\ndef cfg = rootProject.ext.android\ndef appId = rootProject.ext.appId\n\nandroid {\n    compileSdkVersion cfg.compileSdkVersion\n\n    defaultConfig {\n        if (!isModule) {\n            applicationId appId.module2\n        }\n        minSdkVersion cfg.minSdkVersion\n        targetSdkVersion cfg.targetSdkVersion\n        versionCode cfg.versionCode\n        versionName cfg.versionName\n        testInstrumentationRunner \"android.support.test.runner.AndroidJUnitRunner\"\n        javaCompileOptions {\n            annotationProcessorOptions {\n                arguments = [moduleName: project.getName()]\n            }\n        }\n\n        //添加一条 boolean类型的变量\n        buildConfigField(\"boolean\", \"isModule\", String.valueOf(isModule))\n\n        sourceSets {\n            main {\n                if (isModule) {\n                    manifest.srcFile 'src/main/AndroidManifest.xml'\n                } else {\n                    manifest.srcFile 'src/main/module/AndroidManifest.xml'\n                    java.srcDirs 'src/main/module/java', 'src/main/java'\n                }\n            }\n        }\n    }\n\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n\n}\n\ndependencies {\n    implementation fileTree(dir: 'libs', include: ['*.jar'])\n    implementation 'com.android.support:appcompat-v7:26.1.0'\n    implementation 'com.android.support.constraint:constraint-layout:1.0.2'\n    testImplementation 'junit:junit:4.12'\n    androidTestImplementation 'com.android.support.test:runner:1.0.1'\n    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'\n\n    annotationProcessor project(':easy-compiler')\n    implementation project(':base')\n}\n"
  },
  {
    "path": "module2/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "module2/src/androidTest/java/com/xsm/module2/ExampleInstrumentedTest.java",
    "content": "package com.xsm.module2;\n\nimport android.content.Context;\nimport android.support.test.InstrumentationRegistry;\nimport android.support.test.runner.AndroidJUnit4;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\nimport static org.junit.Assert.*;\n\n/**\n * Instrumented test, which will execute on an Android device.\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\n@RunWith(AndroidJUnit4.class)\npublic class ExampleInstrumentedTest {\n    @Test\n    public void useAppContext() throws Exception {\n        // Context of the app under test.\n        Context appContext = InstrumentationRegistry.getTargetContext();\n\n        assertEquals(\"com.xsm.module2\", appContext.getPackageName());\n    }\n}\n"
  },
  {
    "path": "module2/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n          package=\"com.xsm.module2\">\n\n    <application>\n        <activity android:name=\".Module2MainActivity\"/>\n    </application>\n\n</manifest>\n"
  },
  {
    "path": "module2/src/main/java/com/xsm/module2/Module2MainActivity.java",
    "content": "package com.xsm.module2;\n\nimport android.support.v7.app.AppCompatActivity;\nimport android.os.Bundle;\n\nimport com.xsm.easy.annotation.Route;\n\n@Route(path = \"/module2/module2main\")\npublic class Module2MainActivity extends AppCompatActivity {\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_module2_main);\n    }\n}\n"
  },
  {
    "path": "module2/src/main/module/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n          package=\"com.xsm.module2\">\n\n    <application\n        android:allowBackup=\"true\"\n        android:icon=\"@mipmap/ic_launcher\"\n        android:label=\"@string/app_name\"\n        android:roundIcon=\"@mipmap/ic_launcher_round\"\n        android:supportsRtl=\"true\"\n        android:theme=\"@style/AppTheme\">\n        <activity android:name=\".Module2MainActivity\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity>\n    </application>\n\n</manifest>"
  },
  {
    "path": "module2/src/main/res/drawable/ic_launcher_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportHeight=\"108\"\n    android:viewportWidth=\"108\">\n    <path\n        android:fillColor=\"#26A69A\"\n        android:pathData=\"M0,0h108v108h-108z\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M9,0L9,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,0L19,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M29,0L29,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M39,0L39,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M49,0L49,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M59,0L59,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M69,0L69,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M79,0L79,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M89,0L89,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M99,0L99,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,9L108,9\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,19L108,19\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,29L108,29\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,39L108,39\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,49L108,49\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,59L108,59\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,69L108,69\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,79L108,79\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,89L108,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,99L108,99\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,29L89,29\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,39L89,39\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,49L89,49\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,59L89,59\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,69L89,69\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,79L89,79\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M29,19L29,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M39,19L39,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M49,19L49,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M59,19L59,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M69,19L69,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M79,19L79,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\"/>\n</vector>\n"
  },
  {
    "path": "module2/src/main/res/drawable-v24/ic_launcher_foreground.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        xmlns:aapt=\"http://schemas.android.com/aapt\"\n        android:width=\"108dp\"\n        android:height=\"108dp\"\n        android:viewportHeight=\"108\"\n        android:viewportWidth=\"108\">\n    <path\n        android:fillType=\"evenOdd\"\n        android:pathData=\"M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z\"\n        android:strokeColor=\"#00000000\"\n        android:strokeWidth=\"1\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                android:endX=\"78.5885\"\n                android:endY=\"90.9159\"\n                android:startX=\"48.7653\"\n                android:startY=\"61.0927\"\n                android:type=\"linear\">\n                <item\n                    android:color=\"#44000000\"\n                    android:offset=\"0.0\"/>\n                <item\n                    android:color=\"#00000000\"\n                    android:offset=\"1.0\"/>\n            </gradient>\n        </aapt:attr>\n    </path>\n    <path\n        android:fillColor=\"#FFFFFF\"\n        android:fillType=\"nonZero\"\n        android:pathData=\"M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z\"\n        android:strokeColor=\"#00000000\"\n        android:strokeWidth=\"1\"/>\n</vector>\n"
  },
  {
    "path": "module2/src/main/res/layout/activity_module2_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    tools:context=\"com.xsm.module2.Module2MainActivity\">\n\n    <TextView\n        android:text=\"Module2\"\n        android:layout_gravity=\"center_horizontal\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"/>\n</LinearLayout>\n"
  },
  {
    "path": "module2/src/main/res/mipmap-anydpi-v26/ic_launcher.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/ic_launcher_background\"/>\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\"/>\n</adaptive-icon>"
  },
  {
    "path": "module2/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/ic_launcher_background\"/>\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\"/>\n</adaptive-icon>"
  },
  {
    "path": "module2/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"colorPrimary\">#3F51B5</color>\n    <color name=\"colorPrimaryDark\">#303F9F</color>\n    <color name=\"colorAccent\">#FF4081</color>\n</resources>\n"
  },
  {
    "path": "module2/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">Module2</string>\n</resources>\n"
  },
  {
    "path": "module2/src/main/res/values/styles.xml",
    "content": "<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.DarkActionBar\">\n        <!-- Customize your theme here. -->\n        <item name=\"colorPrimary\">@color/colorPrimary</item>\n        <item name=\"colorPrimaryDark\">@color/colorPrimaryDark</item>\n        <item name=\"colorAccent\">@color/colorAccent</item>\n    </style>\n\n</resources>\n"
  },
  {
    "path": "module2/src/test/java/com/xsm/module2/ExampleUnitTest.java",
    "content": "package com.xsm.module2;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.*;\n\n/**\n * Example local unit test, which will execute on the development machine (host).\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\npublic class ExampleUnitTest {\n    @Test\n    public void addition_isCorrect() throws Exception {\n        assertEquals(4, 2 + 2);\n    }\n}"
  },
  {
    "path": "settings.gradle",
    "content": "include ':app', ':easy-compiler', ':easy-annotation', ':easy-core', ':module1', ':module2', ':base'\n"
  }
]