map = null;
43 | JSONObject dataJson = json.optJSONObject("data");
44 | if (dataJson != null) {
45 | map = CCUtil.convertToMap(dataJson);
46 | }
47 | CC.obtainBuilder(componentName)
48 | .setActionName(actionName)
49 | .setParams(map)
50 | .setContext(webView.getContext())
51 | .build().callAsyncCallbackOnMainThread(new IComponentCallback() {
52 | @Override
53 | public void onResult(CC cc, CCResult result) {
54 | function.onCallBack(result.toString());
55 | }
56 | });
57 | }
58 | }
59 | });
60 | return webView;
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/demo_component_jsbridge/src/main/java/com/billy/cc/demo/component/jsbridge/JsBridgeComponent.java:
--------------------------------------------------------------------------------
1 | package com.billy.cc.demo.component.jsbridge;
2 |
3 | import com.billy.cc.core.component.CC;
4 | import com.billy.cc.core.component.CCResult;
5 | import com.billy.cc.core.component.IComponent;
6 | import com.billy.cc.core.component.annotation.AllProcess;
7 | import com.github.lzyzsd.jsbridge.BridgeWebView;
8 |
9 | /**
10 | * jsBridge组件
11 | * @author billy.qi
12 | * @since 18/9/15 10:33
13 | */
14 | @AllProcess
15 | public class JsBridgeComponent implements IComponent {
16 | @Override
17 | public String getName() {
18 | return "jsBridge";
19 | }
20 |
21 | @Override
22 | public boolean onCall(CC cc) {
23 | String actionName = cc.getActionName();
24 | switch (actionName) {
25 | case "createWebView":
26 | //由于JsBridgeComponent添加了@AllProcess注解
27 | // 在任意进程可以调用此action来创建一个新的面向组件封装的WebView
28 | return createWebView(cc);
29 | default:
30 | CC.sendCCResult(cc.getCallId(), CCResult.errorUnsupportedActionName());
31 | break;
32 | }
33 | return false;
34 | }
35 |
36 | private boolean createWebView(CC cc) {
37 | BridgeWebView webView = BridgeWebViewHelper.createWebView(cc.getContext());
38 | CC.sendCCResult(cc.getCallId(), CCResult.success("webView", webView));
39 | return false;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/demo_component_jsbridge/src/main/java/com/billy/cc/demo/component/jsbridge/WebActivity.java:
--------------------------------------------------------------------------------
1 | package com.billy.cc.demo.component.jsbridge;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 | import android.support.v7.app.AppCompatActivity;
6 | import android.text.TextUtils;
7 |
8 | import com.billy.cc.core.component.CCUtil;
9 | import com.github.lzyzsd.jsbridge.BridgeWebView;
10 |
11 | /**
12 | * 用于demo展示一个网页
13 | * @author billy.qi
14 | * @since 18/9/16 12:45
15 | */
16 | public class WebActivity extends AppCompatActivity {
17 | public static String EXTRA_URL = "url";
18 |
19 | @Override
20 | protected void onCreate(@Nullable Bundle savedInstanceState) {
21 | super.onCreate(savedInstanceState);
22 |
23 | BridgeWebView webView = BridgeWebViewHelper.createWebView(this);
24 | setContentView(webView);
25 |
26 | String url = CCUtil.getNavigateParam(this, EXTRA_URL, null);
27 | if (!TextUtils.isEmpty(url)) {
28 | webView.loadUrl(url);
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/demo_component_jsbridge/src/main/java/com/billy/cc/demo/component/jsbridge/WebComponent.java:
--------------------------------------------------------------------------------
1 | package com.billy.cc.demo.component.jsbridge;
2 |
3 | import com.billy.cc.core.component.CC;
4 | import com.billy.cc.core.component.CCResult;
5 | import com.billy.cc.core.component.CCUtil;
6 | import com.billy.cc.core.component.IComponent;
7 | import com.billy.cc.core.component.annotation.SubProcess;
8 |
9 | /**
10 | * @author billy.qi
11 | * @since 18/9/16 13:26
12 | */
13 | @SubProcess(":web")
14 | public class WebComponent implements IComponent {
15 | @Override
16 | public String getName() {
17 | return "webComponent";
18 | }
19 |
20 | @Override
21 | public boolean onCall(CC cc) {
22 | String actionName = cc.getActionName();
23 | switch (actionName) {
24 | case "openUrl":
25 | return openUrl(cc);
26 | default:
27 | CC.sendCCResult(cc.getCallId(), CCResult.errorUnsupportedActionName());
28 | break;
29 | }
30 |
31 | return false;
32 | }
33 |
34 | private boolean openUrl(CC cc) {
35 | CCUtil.navigateTo(cc, WebActivity.class);
36 | CC.sendCCResult(cc.getCallId(), CCResult.success());
37 | return false;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/demo_component_jsbridge/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/demo_component_jsbridge/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/demo_component_jsbridge/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/demo_component_kt/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/demo_component_kt/build.gradle:
--------------------------------------------------------------------------------
1 | apply from: rootProject.file('cc-settings-demo.gradle')
2 | apply plugin: 'kotlin-android'
3 | apply plugin: 'kotlin-android-extensions'
4 | android {
5 | compileSdkVersion rootProject.compileVersion
6 |
7 | defaultConfig {
8 | minSdkVersion rootProject.demoMinSdkVersion // support v7 minSdkVersion is 9
9 | targetSdkVersion rootProject.compileVersion
10 | versionCode 1
11 | versionName "1.0"
12 |
13 | }
14 |
15 | buildTypes {
16 | release {
17 | minifyEnabled false
18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
19 | }
20 | }
21 |
22 | }
23 |
24 | dependencies {
25 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
26 | implementation "com.android.support:appcompat-v7:${rootProject.supportVersion}"
27 | implementation 'com.android.support.constraint:constraint-layout:1.0.2'
28 | }
29 |
--------------------------------------------------------------------------------
/demo_component_kt/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/demo_component_kt/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/demo_component_kt/src/main/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/demo_component_kt/src/main/debug/java/debug/kt/MyApp.java:
--------------------------------------------------------------------------------
1 | package debug.kt;
2 |
3 | import android.app.Application;
4 |
5 | import com.billy.cc.core.component.CC;
6 |
7 | /**
8 | * @author billy.qi
9 | * @since 18/9/15 10:38
10 | */
11 | public class MyApp extends Application {
12 | @Override
13 | public void onCreate() {
14 | super.onCreate();
15 | CC.enableVerboseLog(true);
16 | CC.enableDebug(true);
17 | CC.enableRemoteCC(true);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/demo_component_kt/src/main/java/com/billy/cc/demo/component/kt/KtComponent.kt:
--------------------------------------------------------------------------------
1 | package com.billy.cc.demo.component.kt
2 |
3 | import android.app.Activity
4 | import android.content.Intent
5 | import com.billy.cc.core.component.CC
6 | import com.billy.cc.core.component.CCResult
7 | import com.billy.cc.core.component.IComponent
8 |
9 | /**
10 | * kotlin component demo
11 | * @author billy.qi
12 | */
13 | class KtComponent : IComponent {
14 |
15 | override fun getName(): String {
16 | return "demo.ktComponent"
17 | }
18 |
19 | override fun onCall(cc: CC): Boolean {
20 | when (cc.actionName){
21 | "showActivity" -> openActivity(cc)
22 | //确保每个逻辑分支上都会调用CC.sendCCResult将结果发送给调用方
23 | else -> CC.sendCCResult(cc.callId, CCResult.errorUnsupportedActionName())
24 | }
25 | return false
26 | }
27 |
28 | private fun openActivity(cc: CC) {
29 | val context = cc.context
30 | val intent = Intent(context, MainActivity::class.java)
31 | if (context !is Activity) {
32 | //调用方没有设置context或app间组件跳转,context为application
33 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
34 | }
35 | context.startActivity(intent)
36 | //需要确保每个逻辑分支都会调用CC.sendCCResult将结果发送给调用方
37 | CC.sendCCResult(cc.callId, CCResult.success())
38 | }
39 | }
--------------------------------------------------------------------------------
/demo_component_kt/src/main/java/com/billy/cc/demo/component/kt/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.billy.cc.demo.component.kt
2 |
3 | import android.os.Bundle
4 | import android.support.v7.app.AppCompatActivity
5 | import android.view.Gravity
6 | import android.widget.TextView
7 |
8 | class MainActivity : AppCompatActivity() {
9 |
10 | override fun onCreate(savedInstanceState: Bundle?) {
11 | super.onCreate(savedInstanceState)
12 | val textView : TextView = TextView(this)
13 | textView.gravity = Gravity.CENTER
14 | textView.setText("kotlin page\nclick to finish!")
15 | textView.setOnClickListener({
16 | finish()
17 | })
18 | setContentView(textView)
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/demo_interceptors/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/demo_interceptors/build.gradle:
--------------------------------------------------------------------------------
1 | ext.alwaysLib = true //虽然apply了cc-settings-2.gradle,但一直作为library编译,否则别的组件依赖此module时会报错
2 | apply from: rootProject.file('cc-settings-demo.gradle')
3 |
4 | android {
5 | compileSdkVersion rootProject.compileVersion
6 | buildToolsVersion rootProject.buildVersion
7 |
8 | defaultConfig {
9 | minSdkVersion rootProject.demoMinSdkVersion
10 | targetSdkVersion rootProject.compileVersion
11 | versionCode 1
12 | versionName "1.0"
13 | }
14 |
15 | buildTypes {
16 | release {
17 | minifyEnabled false
18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
19 | }
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/demo_interceptors/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/demo_interceptors/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/demo_interceptors/src/main/java/com/billy/cc/demo/interceptors/LogInterceptor.java:
--------------------------------------------------------------------------------
1 | package com.billy.cc.demo.interceptors;
2 |
3 | import android.util.Log;
4 |
5 | import com.billy.cc.core.component.CCResult;
6 | import com.billy.cc.core.component.Chain;
7 | import com.billy.cc.core.component.IGlobalCCInterceptor;
8 |
9 | /**
10 | * 示例全局拦截器:日志打印
11 | * @author billy.qi
12 | * @since 18/5/26 11:42
13 | */
14 | public class LogInterceptor implements IGlobalCCInterceptor {
15 | private static final String TAG = "LogInterceptor";
16 |
17 | @Override
18 | public int priority() {
19 | return 1;
20 | }
21 |
22 | @Override
23 | public CCResult intercept(Chain chain) {
24 | Log.i(TAG, "============log before:" + chain.getCC());
25 | CCResult result = chain.proceed();
26 | Log.i(TAG, "============log after:" + result);
27 | return result;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/demo_interceptors/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/docs/ChangeLog.md:
--------------------------------------------------------------------------------
1 |
2 | # 更新日志
3 |
4 | [点击这里查看最新的更新日志](https://luckybilly.github.io/CC-website/#/changelog)
5 |
6 | - 2019.01.30 V2.1.2
7 |
8 | ~~~
9 | 1. 修复主线程同步调用跨进程组件时超时设置失效的问题
10 | 2. 升级cc-register插件到1.0.7:修复gradle版本号有多个小数点(如:4.10.1)时cc-register插件报错的问题
11 | 3. 新增一个错误码:-12(组件不支持该actionName)
12 | 在IComponent.onCall(cc)方法中通过CC.sendCCResult(callId, CCResult.errorUnsupportedActionName())来返回该error
13 | 4. CC支持不使用Key设置一个param,CCResult支持不使用Key设置一个data (建议:仅在只有1个参数的时候使用):
14 |
15 | //通过setParamWithNoKey添加一个无key的参数(只支持1个)
16 | CC.obtainBuilder("ComponentA")...setParamWithNoKey("billy")...build().callAsync();
17 | //对应的取值方式为
18 | String name = cc.getParamItemWithNoKey();
19 | //支持取值时提供一个默认值
20 | String name = cc.getParamItemWithNoKey("");
21 |
22 | //通过successWithNoKey构建一个无key返回值的CCResult(只支持1个)
23 | CCResult.successWithNoKey("billy");
24 | //对应的取值方式为
25 | String name = result.getDataItemWithNoKey();
26 | //支持取值时提供一个默认值
27 | String name = result.getDataItemWithNoKey("");
28 | ~~~
29 | - 2018.10.05 V2.1.0
30 |
31 |
32 | 1. 在定义组件时可通过实现IMainThread接口指定不同action被调用时component.onCall方法是否在主线程运行
33 | 2. 使用CCUtil.navigateTo、CCUtil.getNavigateCallId及CCUtil.getNavigateParam等工具方法来简化页面跳转相关的代码
34 |
35 | 链接:
36 |
37 | [IMainThread](../cc/src/main/java/com/billy/cc/core/component/IMainThread.java)
38 | [CCUtil](../cc/src/main/java/com/billy/cc/core/component/CCUtil.java)
39 |
40 |
41 | - 2018.09.16 V2.0.0 全新升级
42 |
43 |
44 | 1. 重构跨进程通信机制,新增支持应用内部跨进程组件调用
45 | 2. 新增通过拦截器(继承BaseForwardInterceptor)转发组件调用,可用于A/B-Test
46 | 3. 自动注册插件从通用的AutoRegister改为CC定制版的cc-register
47 | 4. 大幅简化cc-settings.gradle,将大部分功能移至cc-register插件中完成
48 | 5. 优化组件独立运行的步骤:可直接在Android studio中点击运行按钮(主app需要排除当前独立运行的组件,还是通过local.properties中添加module_name=true来实现)
49 |
50 | 详情请看[升级指南](../2.0升级指南.MD)
51 |
52 | - 2018.06.04 V1.1.0 重大更新
53 |
54 |
55 | 1. 新增支持全局拦截器:
56 | 实现IGlobalCCInterceptor接口即可,插件会自动完成注册 (配合最新的cc-settings.gradle文件使用)
57 | CC调用时,可通过withoutGlobalInterceptor()对当前CC禁用所有全局拦截器
58 | 2. 跨app调用时,新增支持自定义类型的参数
59 | 实现IParamJsonConverter接口即可,插件会自动完成注册 (配合最新的cc-settings.gradle文件使用)
60 | 自定义Bean的类型无需实现Serializable/Parcelable接口
61 | 需要跨app传递的bean类型需要下沉到公共库,通信双方都依赖此库以实现类型发送和接受
62 | 参考:LoginActivity
63 | 3. 新增一种状态码: -11
64 | 只会在跨app调用组件时发生,代表参数传递错误,可以通过查看Logcat了解详细信息
65 | 4. 跨app调用默认状态改为关闭,可手动打开: CC.enableRemoteCC(true)
66 | 5. 修改cc-settings.gradle
67 | 增加IGlobalCCInterceptor和IParamJsonConverter的自动注册配置
68 | 将autoregister的参数配置改为可添加的方式(原来是覆盖式),参考:cc-settings-demo.gradle
69 |
70 | 链接:
71 |
72 | 全局拦截器:
73 | [IGlobalCCInterceptor](../cc/src/main/java/com/billy/cc/core/component/IGlobalCCInterceptor.java)
74 |
75 | 跨app调用时的参数转换工具:
76 | [IParamJsonConverter](../cc/src/main/java/com/billy/cc/core/component/IParamJsonConverter.java)
77 |
78 | [LoginActivity](../demo_component_b/src/main/java/com/billy/cc/demo/component/b/LoginActivity.java)
79 |
80 | [cc-settings-demo.gradle](../cc-settings-demo.gradle)
81 |
82 | - 2018.05.17 V1.0.0版 Fix issue [#23](https://github.com/luckybilly/CC/issues/23)
83 |
84 |
85 | 修复跨app调用组件时传递的参数为null导致`cc.getParamItem(key)`抛异常的问题
86 |
87 | - 2018.04.06 更新cc-settings.gradle
88 |
89 |
90 | 1. 废弃ext.runAsApp参数设置,(目前仍然兼容其功能,但不再推荐使用)
91 | 2. 新增使用ext.mainApp=true来标记主app module
92 | 3. 新增依赖组件的方式(功能见README,用法示例见demo/build.gradle):
93 | dependencies {
94 | addComponent 'demo_component_a' //会默认添加依赖:project(':demo_component_a')
95 | addComponent 'demo_component_kt', project(':demo_component_kt') //module方式
96 | addComponent 'demo_component_b', 'com.billy.demo:demo_b:1.1.0' //maven方式
97 | }
98 |
99 |
100 | - 2018.02.09 V0.5.0版
101 |
102 |
103 | 在组件作为app运行时,通过显式调用如下代码来解决在部分设备上无法被其它app调用的问题
104 | CC.enableRemoteCC(true);//建议在Application.onCreate方法中调用
105 |
106 | - 2018.02.07 V0.4.0版
107 |
108 |
109 | 异步调用时也支持超时设置(setTimeout)
110 |
111 | - 2017.12.23 V0.3.1版
112 |
113 |
114 | 1. 为获取CC和CCResult对象中Map里的对象提供便捷方法,无需再进行类型判断和转换
115 | WhateEverClass classObj = cc.getParamItem(String key, WhateEverClass defaultValue)
116 | WhateEverClass classObj = cc.getParamItem(String key)
117 | WhateEverClass classObj = ccResult.getDataItem(String key, WhateEverClass defaultValue)
118 | WhateEverClass classObj = ccResult.getDataItem(String key)
119 | 2. demo中新增演示跨组件获取Fragment对象
120 |
121 |
122 |
123 | - 2017.12.09 V0.3.0版
124 |
125 |
126 | 添加Activity及Fragment生命周期关联的功能并添加对应的demo
127 |
128 | - 2017.11.29 V0.2.0版
129 |
130 |
131 | 将跨进程调用接收LocalSocket信息的线程放入到线程池中
132 | 完善demo
133 |
134 | - 2017.11.27 V0.1.1版
135 |
136 |
137 | 1. 优化超时的处理流程
138 | 2. 优化异步返回CCResult的处理流程
139 |
140 | - 2017.11.24 V0.1.0版 初次发布
--------------------------------------------------------------------------------
/docs/Q&A.md:
--------------------------------------------------------------------------------
1 |
2 | ## 常见问题
3 |
4 | - 运行demo时调用ComponentB出现页面打不开
5 |
6 | - 2.0.0版以前,请参考[issue](https://github.com/luckybilly/CC/issues/5)
7 | - 2.0.0版以后,有些高版本手机的权限管理中有"后台弹出界面"的权限设置(比如vivo手机:设置-更多设置-权限管理),给CC和Demo_B开启这个权限即可
8 |
9 |
10 | - 无法调用到组件
11 |
12 | 1. 请按照README文档的集成说明排查
13 | 2. 请确认调用的组件名称(CC.obtainBuilder(componentName)与组件类定定义的名称(getName()的返回值)是否一致
14 | 3. 请确认actionName是否与组件中定义的一致
15 | 4. 开发阶段,若跨app调用失败(错误码: -5),请确认在调用组件之前是否启用了跨app组件调用功能:CC.enableRemoteCC(true);
16 | 5. 请检查gradle console,查看cc-register打印的自动注册日志,示例如下:
17 | ```
18 | insert register code to file:/Users/billy/Documents/github/CC/demo/build/intermediates/transforms/cc-register/release/0.jar
19 | com/billy/cc/demo/component/a/ComponentA
20 | com/billy/cc/demo/component/kt/KtComponent
21 | com/billy/cc/demo/lifecycle/LifecycleComponent
22 | com/billy/cc/demo/component/jsbridge/JsBridgeComponent
23 | com/billy/cc/demo/component/jsbridge/WebComponent
24 | generate code into:com/billy/cc/core/component/ComponentManager.class
25 |
26 | insert register code to file:/Users/billy/Documents/github/CC/demo/build/intermediates/transforms/cc-register/release/0.jar
27 | com/billy/cc/demo/interceptors/LogInterceptor
28 | generate code into:com/billy/cc/core/component/GlobalCCInterceptorManager.class
29 |
30 | insert register code to file:/Users/billy/Documents/github/CC/demo/build/intermediates/transforms/cc-register/release/0.jar
31 | com/billy/cc/demo/base/GsonParamConverter
32 | generate code into:com/billy/cc/core/component/remote/RemoteParamUtil.class
33 | cc-register insert code cost time: 59 ms
34 | cc-register generated a provider: /Users/billy/Documents/github/CC/demo/build/intermediates/transforms/cc-register/release/26/com/billy/cc/core/providers/CC_Provider_web.class
35 | cc-register cost time: 260 ms
36 |
37 | ```
38 |
39 | - 组件作为app独立运行调试,在主app中调用该组件时,该组件中新增/修改的代码未生效
40 |
41 |
42 | 出现这个问题的原因是:
43 | 主APP打包时已经将该独立运行的组件包含在内了,调用组件时优先调用app内部的组件,从而忽略了独立运行的组件
44 | 解决方法:
45 | 1. 在local.properties中新增一行配置 modulename=true //注:modulename为独立运行组件的module名称
46 | 2. 重新打包运行一次主app module(目的是为了将独立运行的组件module从主app的依赖列表中排除)
47 |
48 | - 调用异步实现的组件时,IComponentCallback.onResult方法没有执行
49 |
50 |
51 | 1. 请检查组件实现的代码中是否每个逻辑分支是否最终都会调用CC.sendCCResult(...)方法
52 | 包括if-else/try-catch/switch-case/按返回键或主动调用finish()等情况
53 | 2. 请检查组件实现的代码中该action分支是否返回为true
54 | 返回值的意义在于告诉CC引擎:调用结果是否异步发送(执行CC.sendCCResult(...)方法)
55 |
56 | - 跨app调用组件时,onCall方法执行到了startActivity,但页面没打开
57 |
58 |
59 | 1. 请在手机系统的权限管理中对组件所在的app赋予自启动权限
60 | 2. 请检查被调用的app里是否设置了CC.enableRemoteCC(false),应该设置为true(默认值为false)
61 |
62 | - 使用ActionProcessor来处理多个action,单独组件作为apk运行时能正常工作,打包到主app中则不能正常工作
63 |
64 | ```groovy
65 | //某个组件使用自定义的cc-settings-2.gradle文件添加了额外的配置时,主工程也要使用相同的gradle文件
66 | apply from: rootProject.file(cc-settings-2.gradle)
67 | ```
68 | 参考[demo/build.gradle](https://github.com/luckybilly/CC/blob/master/demo/build.gradle)中的配置
69 |
70 | - 如何实现context.startActivityForResult的功能
71 |
72 |
73 | 1. 使用方式同普通页面跳转
74 | 2. 在onCall方法里返回true
75 | 3. 在跳转的Activity中回调信息时,不用setResult, 通过CC.sendCCResult(callId, result)来回调结果
76 | 4. 调用组件时,使用cc.callAsyncCallbackOnMainThread(new IComponentCallback(){...})来接收返回结果
77 |
78 | - ComponentName和ActionName这些常量字符串如何管理
79 |
80 |
81 | 建议采用以下2种方式中的一种来进行管理:
82 | 1. 每个组件内部维护一个常量类,将组件自己的ComponentName、ActionName及用到的其它组件的字符串统一管理
83 | 2. 创建一个公共module,为每个组件创建一个常量类,包含对应组件的名称及action字符串
84 |
85 | - 组件之间通信的自定义类型如何处理
86 | - 下沉到公共库中,作为公共类型
87 | - 适用于使用频次高或对性能要求特别敏感的场景
88 | - json传递 & bean冗余:即在每个用到此类型的组件,通过冗余bean的方式来传递
89 | - 适用于使用频次较低且对性能要求不是十分敏感的场景
90 |
91 | demo_component_b中的模拟登录功能[演示了自定义类型的传递](../demo_component_b/src/main/java/com/billy/cc/demo/component/b/LoginActivity.java#L89:20)
92 |
93 | - 主module可以实现IComponent 让其他组件来调用吗?
94 |
95 |
96 | 可以,参考demo里的LifecycleComponent
97 | 就是通过这种方式,让组件module可以调用到未解耦出来的业务,从而达到渐进式组件化的目的
98 |
99 | - 在A Module 的 a 界面 尝试跳转到 B Module 的 b 界面,跳转结果却是再次跳转到 a 界面,是怎么回事呢?
100 |
101 |
102 | 请确认是不是布局文件重名了,比如:main_activity.xml
103 |
104 | 未完待续...
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
19 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckybilly/CC/368b8dd029b997ee5a36fc3c6e2b51d4fd82021b/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Thu Sep 06 10:25:29 CST 2018
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/image/CC.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckybilly/CC/368b8dd029b997ee5a36fc3c6e2b51d4fd82021b/image/CC.gif
--------------------------------------------------------------------------------
/image/CC_QQ.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckybilly/CC/368b8dd029b997ee5a36fc3c6e2b51d4fd82021b/image/CC_QQ.png
--------------------------------------------------------------------------------
/image/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckybilly/CC/368b8dd029b997ee5a36fc3c6e2b51d4fd82021b/image/icon.png
--------------------------------------------------------------------------------
/image/lct/lct_cross_app.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckybilly/CC/368b8dd029b997ee5a36fc3c6e2b51d4fd82021b/image/lct/lct_cross_app.png
--------------------------------------------------------------------------------
/image/lct/lct_in_app.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckybilly/CC/368b8dd029b997ee5a36fc3c6e2b51d4fd82021b/image/lct/lct_in_app.png
--------------------------------------------------------------------------------
/image/shoukuan_alipay.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckybilly/CC/368b8dd029b997ee5a36fc3c6e2b51d4fd82021b/image/shoukuan_alipay.png
--------------------------------------------------------------------------------
/image/shoukuan_wechat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckybilly/CC/368b8dd029b997ee5a36fc3c6e2b51d4fd82021b/image/shoukuan_wechat.png
--------------------------------------------------------------------------------
/image/sst/sst_call_remote_component.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckybilly/CC/368b8dd029b997ee5a36fc3c6e2b51d4fd82021b/image/sst/sst_call_remote_component.png
--------------------------------------------------------------------------------
/image/sst/sst_cc_interceptors.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckybilly/CC/368b8dd029b997ee5a36fc3c6e2b51d4fd82021b/image/sst/sst_cc_interceptors.png
--------------------------------------------------------------------------------
/image/sst/sst_get_remote_service.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luckybilly/CC/368b8dd029b997ee5a36fc3c6e2b51d4fd82021b/image/sst/sst_get_remote_service.png
--------------------------------------------------------------------------------
/pools/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/pools/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion rootProject.compileVersion
5 | buildToolsVersion rootProject.buildVersion
6 |
7 | defaultConfig {
8 | minSdkVersion rootProject.minVersion
9 | targetSdkVersion rootProject.compileVersion
10 | }
11 | }
12 |
13 |
14 | sourceCompatibility = 1.7
15 | targetCompatibility = 1.7
16 |
17 | ext {
18 | bintrayRepo = 'android'
19 | bintrayName = 'objpool'
20 |
21 | publishedGroupId = 'com.billy.android'
22 | libraryName = 'ObjPool'
23 | artifact = 'pools'
24 |
25 | libraryDescription = '线程安全的对象池'
26 |
27 | siteUrl = 'https://github.com/luckybilly/CC'
28 | gitUrl = 'git@github.com:luckybilly/CC.git'
29 |
30 | libraryVersion = '0.0.6' //要发布到 jcenter 上的版本号
31 |
32 | developerId = 'billy'
33 | developerName = 'billy'
34 | developerEmail = 'okkanan@hotmail.com'
35 |
36 | licenseName = 'The Apache Software License, Version 2.0'
37 | licenseUrl = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
38 | allLicenses = ["Apache-2.0"]
39 | }
40 |
41 | apply from: rootProject.file('bintray.gradle')
--------------------------------------------------------------------------------
/pools/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/billy/Library/Android/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | # Uncomment this to preserve the line number information for
20 | # debugging stack traces.
21 | #-keepattributes SourceFile,LineNumberTable
22 |
23 | # If you keep the line number information, uncomment this to
24 | # hide the original source file name.
25 | #-renamesourcefileattribute SourceFile
26 |
--------------------------------------------------------------------------------
/pools/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/pools/src/main/java/com/billy/android/pools/ObjPool.java:
--------------------------------------------------------------------------------
1 | package com.billy.android.pools;
2 |
3 | import java.util.concurrent.ConcurrentLinkedQueue;
4 |
5 | /**
6 | * 线程安全的对象池
7 | *
8 | * 使用方法:
9 | *
10 | * //创建一个新对象池
11 | * ObjPool<ImageView, Context> pool = new ObjPool<>(){
12 | * protected ImageView newInstance(Context r) {
13 | * return new ImageView(r);
14 | * }
15 | * };
16 | * pool.get(context); //获取一个实例
17 | * pool.put(imageView); //回收一个实例到对象池
18 | * pool.clear(); //清空对象池
19 | *
20 | *
21 | * @param 要创建的对象
22 | * @param 创建对象所需的参数
23 | */
24 | public abstract class ObjPool {
25 |
26 | protected ConcurrentLinkedQueue list;
27 |
28 | /**
29 | * 创建一个对象池,不限制缓存数量
30 | */
31 | public ObjPool() {
32 | list = new ConcurrentLinkedQueue<>();
33 | }
34 |
35 | /**
36 | * 从对象池中获取一个实例
37 | * 优先从缓存中获取,如果缓存中没有实例,则创建一个实例并返回
38 | * @param r 创建一个新实例需要的参数
39 | * @return 获取的实例
40 | */
41 | public T get(R r) {
42 | T t = list.poll();
43 | if (t == null) {
44 | t = newInstance(r);
45 | }
46 | if (t != null && t instanceof Initable) {
47 | ((Initable) t).init(r);
48 | }
49 | return t;
50 | }
51 |
52 |
53 | /**
54 | * 接收一个实例放到对象池中
55 | * @param t 要放入对象池的实例
56 | */
57 | public void put(T t) {
58 | if (t != null) {
59 | if (t instanceof Resetable) {
60 | ((Resetable) t).reset();
61 | }
62 | list.offer(t);
63 | }
64 | }
65 |
66 | /**
67 | * 清空对象池
68 | * 推荐在确定不再需要此对象池的时候调用此方法来清空缓存的实例
69 | */
70 | public void clear() {
71 | list.clear();
72 | }
73 |
74 | /**
75 | * 创建新的实例
76 | * @param r 创建对象所需的参数
77 | * @return 新的实例
78 | */
79 | protected abstract T newInstance(R r);
80 |
81 | public interface Resetable {
82 | void reset();
83 | }
84 | public interface Initable {
85 | void init(R r);
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':cc', ':demo_component_kt', ':cc-register', ':demo_component_jsbridge'
2 | include ':pools'
3 | include ':demo'
4 | include ':demo_component_a'
5 | include ':demo_component_b'
6 | include ':demo_base'
7 | include ':demo_interceptors'
8 | include ':android_internal'
9 |
--------------------------------------------------------------------------------