AppJoint
Simple tool to make your multi-module Android development easier!
Only 3 annotations and 1 function call are included.
Getting started
- Add the AppJoint plugin dependency to the
build.gradle
file in project root:
buildscript {
...
dependencies {
...
classpath 'io.github.prototypez:app-joint:{latest_version}'
}
}
- Add the AppJoint dependency to every module:
dependencies {
...
implementation "io.github.prototypez:app-joint-core:{latest_version}"
}
- Apply the AppJoint plugin to your main app module:
apply plugin: 'com.android.application'
apply plugin: 'app-joint'
Cross module method invocation
Assuming the router
module is a common module that all the other modules depend on it. Then we can define interfaces that each module wish to provide for other modules to use in the router
module. For example, the module1
module provides the Module1Service
interface for other modules to use:
interface Module1Service {
/**
* start Activity from moduel1
*/
fun startActivityOfModule1(context: Context)
/**
* get Fragment from module1
*/
fun obtainFragmentOfModule1(): Fragment
/**
* call synchronous method from module1
*/
fun callMethodSyncOfModule1(): String
/**
* call asynchronous method from module1
*/
fun callMethodAsyncOfModule1(callback: Module1Callback<Module1Entity>)
/**
* get RxJava Observable from module1
*/
fun observableOfModule1(): Observable<Module1Entity>
}
Then we write an implementation of it inside the module1
module:
@ServiceProvider
class Module1ServiceImpl : Module1Service {
override fun startActivityOfModule1(context: Context) {
Module1Activity.start(context)
}
override fun obtainFragmentOfModule1(): Fragment {
return Module1Fragment.newInstance()
}
override fun callMethodSyncOfModule1(): String {
return "syncMethodResultModule1"
}
override fun callMethodAsyncOfModule1(callback: Module1Callback<Module1Entity>) {
Thread { callback.onResult(Module1Entity("asyncMethodResultModule1")) }.start()
}
override fun observableOfModule1(): Observable<Module1Entity> {
return Observable.just(Module1Entity("rxJavaResultModule1"))
}
}
Note that we add a @ServiceProvider
annotation on the class。
Now, we can get the instance of Module1Service
anywhere in any module,as long as we write the codes below:
Module1Service service = AppJoint.service(Module1Service.class);
Application
logic of modules
Merge custom You can create a custom Application
class for each module in order to run the module standalone, for example:
// it supports initializing module applications by priority,
// if priorities are not defined, they are initialized with an unknown sequence
@ModuleSpec( priority = 1)
class Module1Application : Application() {
override fun onCreate() {
super.onCreate()
// do module1 initialization
Log.i("module1", "module1 init is called")
}
}
Note that the custom Application
class is annotated with the @ModuleSpec
annotation.
Then add the @AppSpec
annotation to the custom Application
class of your main application module.
@AppSpec
class App : Application() {
override fun onCreate() {
super.onCreate()
Log.i("app", "app init is called")
}
}
AppJoint can ensure that, when the lifecycle methods(such as onCreate
, attachBaseContext
) of the class annotated with @AppSpec
are called, the same lifecycle methods of the class annoatated with @ModuleSpec
will be called, too.
Multi-implementation for cross module interfaces
We can name implementations for an specific interface to provide more implementations for this interface.
@ServiceProvider("anotherImpl")
class Module1ServiceAnotherImpl : Module1Service {
...
}
Then we only need to provide the name of an implementation to get proper implementation of the interface:
Module1Service service = AppJoint.service(Module1Service.class, "anotherImpl");
FAQ
-
Q: Does AppJoint support Instant Run?
A: Yes,it's based on Transform API, so no problem.
-
Q: Do I need to add any Proguard rules for release?
A: No, there's no reflection, so you are safe to use Proguard.
TroubleShooting
-
Error in compile time,
AppJoint class file not found, please check "io.github.prototypez:app-joint-core:{latest_version}" is in your dependency graph.
Solution: First, make sure
"io.github.prototypez:app-joint-core:{latest_version}"
can be visited in your main app module. Second, make sure lineapply plugin: 'app-joint'
is right belowapply plugin: 'com.android.application'
before other plugins.
LICENSE
Copyright (c) 2016-present, AppJoint Contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.