🔥🔥🔥A lightweight cross-process communication component on Android, Kotlin and Coroutines both supported.
A lightweight cross-process communication component on Android。(All versions are supported,only 98kb)
Type | Supported |
---|---|
All versions for Android | ✅ |
Kotlin | ✅ |
Sync call | ✅ |
Async Call | ✅ |
Coroutines | ✅ |
Thread-Safe | ✅ |
Many(Client)-To-Many(Service) | ✅ |
Method's Parameters:1、Basic type;2、Object which is implemented Parcelable;3、List<out Parcelable> ;4、List<out String> ;5、List<out Int> ;6、List<out Charsequence> |
✅ |
Broadcast message | ✅ |
Proguard | ✅ |
implementation 'com.github.Softtanck:RAMessage:2.0.0'
- Defined the interface at client side;
interface RaTestInterface : IRaMessageInterface {
fun getAFood(): Food?
fun getAFoodWithParameter(foodName: String): Food?
fun getAllFoods(): List<Food>?
fun eatFood()
fun buyFood(): Boolean
fun getFoodName(): String
fun setFoodName(foodName: String): String
suspend fun suspendBuyFood(): Boolean?
suspend fun suspendGetFood(): Food?
}
- Use method of
RaClientApi.INSTANCE.create(RaTestInterface::class.java)
after bind is successful;
RaClientApi.INSTANCE.bindRaConnectionService(this, componentName, object : BindStatusChangedListener {
override fun onConnectedToRaServices(componentName: ComponentName) {
Log.d(TAG, "connectedToRaServices: $this-$componentName")
val testInterface = RaClientApi.INSTANCE.create(componentName = componentName, service = RaTestInterface::class.java)
// 1. Get a food from other process
var remoteFood: Food? = testInterface.getAFood()
Log.d(TAG, "getAFood result: $remoteFood")
if (remoteFood?.name != "Apple") {
throw IllegalStateException("Get a food from other process failed")
}
// 2. Get a food with parameter
remoteFood = testInterface.getAFoodWithParameter("Banana")
Log.d(TAG, "getAFoodWithParameter: $remoteFood")
// 3. Get all foods
val allFoods = testInterface.getAllFoods()
Log.d(TAG, "getAllFoods: $allFoods, ${allFoods?.size}")
// 4. Eat food
testInterface.eatFood()
// 5. Buy a food
val buyFoodResult = testInterface.buyFood()
Log.d(TAG, "buyFood: $buyFoodResult")
// 6. Get a food name
val foodName = testInterface.getFoodName()
Log.d(TAG, "getFoodName: $foodName")
// 7. Set food name
val changedFoodName = testInterface.setFoodName("Pear")
Log.d(TAG, "setFoodName: $changedFoodName")
// 8. Suspend
lifecycleScope.launch(Dispatchers.IO) {
// 8.1 buy food
val suspendBuyFoodResult = testInterface.suspendBuyFood()
Log.d(TAG, "suspendBuyFood: $suspendBuyFoodResult")
// 8.2 get food
val suspendGetFood = testInterface.suspendGetFood()
Log.d(TAG, "suspendGetFood: $suspendGetFood")
}
}
override fun onConnectRaServicesFailed(componentName: ComponentName) {
Log.d(TAG, "onConnectRaServicesFailed: $componentName")
}
override fun onDisconnectedFromRaServices(componentName: ComponentName, @DisconnectedReason disconnectedReason: Int) {
Log.d(TAG, "disconnectedFromRaServices: $disconnectedReason-$componentName")
}
})
- extend
BaseConnectionService
- Implement
RaTestInterface
interface MyServerTestFunImpl : RaTestInterface {
override fun getAFood(): Food? {
Log.d(TAG, "[SERVER] getAFood: Service is invoked")
return testFood
}
override fun getAFoodWithParameter(foodName: String): Food? {
Log.d(TAG, "[SERVER] getAFoodWithParameter: Service is invoked, foodName:$foodName")
return testFood.apply {
name = foodName
}
}
override fun getAllFoods(): List<Food>? {
Log.d(TAG, "[SERVER] getAllFoods")
return mutableListOf<Food>().apply {
repeat(10) {
add(testFood)
}
}
}
override fun eatFood() {
Log.d(TAG, "[SERVER] eatFood")
}
override fun buyFood(): Boolean {
Log.d(TAG, "[SERVER] buyFood")
return true
}
override fun getFoodName(): String {
Log.d(TAG, "[SERVER] getFoodName")
return testFood.name
}
override fun setFoodName(foodName: String): String {
Log.d(TAG, "[SERVER] setFoodName: $foodName")
return testFood.name
}
override suspend fun suspendBuyFood(): Boolean {
Log.d(TAG, "[SERVER] suspendBuyFood")
return true
}
override suspend fun suspendGetFood(): Food {
Log.d(TAG, "[SERVER] suspendGetFood")
return testFood
}
}
-keep class * extends com.softtanck.IRaMessageInterface { *;}
-keep interface * extends com.softtanck.IRaMessageInterface { *;}
-keep class com.softtanck.ramessageclient.core.engine.retrofit.RemoteServiceMethod { *; }
-keep class com.softtanck.ramessageservice.** { *; }
一个高性能且线程安全的IPC通信框架。(Android全平台支持,仅98kb)
Type | Supported |
---|---|
Android所有版本 | ✅ |
Kotlin | ✅ |
同步调用 | ✅ |
异步调用 | ✅ |
协程 | ✅ |
线程安全 | ✅ |
多个客户端<->多个服务端 | ✅ |
支持接口参数、返回参数为:1、基本类型;2、实现了Parcelable的对象;3、List<out Parcelable> ;4、List<out String> ;5、List<out Int> ;6、List<out Charsequence> |
✅ |
广播消息 | ✅ |
混淆 | ✅ |
implementation 'com.github.Softtanck:RAMessage:2.0.0'
- 先在客户端定义想要IPC的接口;
interface RaTestInterface : IRaMessageInterface {
fun getAFood(): Food?
fun getAFoodWithParameter(foodName: String): Food?
fun getAllFoods(): List<Food>?
fun eatFood()
fun buyFood(): Boolean
fun getFoodName(): String
fun setFoodName(foodName: String): String
suspend fun suspendBuyFood(): Boolean?
suspend fun suspendGetFood(): Food?
}
- 在客户端绑定远程服务成功后,通过
RaClientApi.INSTANCE.create(ComponentName, RaTestInterface::class.java)
方法即可获得对应服务,然后调用对应接口即可;
// 1. 提供被绑定的远程服务器名字;2. 在绑定成功后,调用远程服务即可;
RaClientApi.INSTANCE.bindRaConnectionService(this, componentName, object : BindStatusChangedListener {
override fun onConnectedToRaServices(componentName: ComponentName) {
Log.d(TAG, "connectedToRaServices: $this-$componentName")
val testInterface = RaClientApi.INSTANCE.create(componentName = componentName, service = RaTestInterface::class.java)
// 1. Get a food from other process
var remoteFood: Food? = testInterface.getAFood()
Log.d(TAG, "getAFood result: $remoteFood")
if (remoteFood?.name != "Apple") {
throw IllegalStateException("Get a food from other process failed")
}
// 2. Get a food with parameter
remoteFood = testInterface.getAFoodWithParameter("Banana")
Log.d(TAG, "getAFoodWithParameter: $remoteFood")
// 3. Get all foods
val allFoods = testInterface.getAllFoods()
Log.d(TAG, "getAllFoods: $allFoods, ${allFoods?.size}")
// 4. Eat food
testInterface.eatFood()
// 5. Buy a food
val buyFoodResult = testInterface.buyFood()
Log.d(TAG, "buyFood: $buyFoodResult")
// 6. Get a food name
val foodName = testInterface.getFoodName()
Log.d(TAG, "getFoodName: $foodName")
// 7. Set food name
val changedFoodName = testInterface.setFoodName("Pear")
Log.d(TAG, "setFoodName: $changedFoodName")
// 8. Suspend
lifecycleScope.launch(Dispatchers.IO) {
// 8.1 buy food
val suspendBuyFoodResult = testInterface.suspendBuyFood()
Log.d(TAG, "suspendBuyFood: $suspendBuyFoodResult")
// 8.2 get food
val suspendGetFood = testInterface.suspendGetFood()
Log.d(TAG, "suspendGetFood: $suspendGetFood")
}
}
override fun onConnectRaServicesFailed(componentName: ComponentName) {
Log.d(TAG, "onConnectRaServicesFailed: $componentName")
}
override fun onDisconnectedFromRaServices(componentName: ComponentName, @DisconnectedReason disconnectedReason: Int) {
Log.d(TAG, "disconnectedFromRaServices: $disconnectedReason-$componentName")
}
})
- 继承
BaseConnectionService
- 实现
RaTestInterface
接口
interface MyServerTestFunImpl : RaTestInterface {
override fun getAFood(): Food? {
Log.d(TAG, "[SERVER] getAFood: Service is invoked")
return testFood
}
override fun getAFoodWithParameter(foodName: String): Food? {
Log.d(TAG, "[SERVER] getAFoodWithParameter: Service is invoked, foodName:$foodName")
return testFood.apply {
name = foodName
}
}
override fun getAllFoods(): List<Food>? {
Log.d(TAG, "[SERVER] getAllFoods")
return mutableListOf<Food>().apply {
repeat(10) {
add(testFood)
}
}
}
override fun eatFood() {
Log.d(TAG, "[SERVER] eatFood")
}
override fun buyFood(): Boolean {
Log.d(TAG, "[SERVER] buyFood")
return true
}
override fun getFoodName(): String {
Log.d(TAG, "[SERVER] getFoodName")
return testFood.name
}
override fun setFoodName(foodName: String): String {
Log.d(TAG, "[SERVER] setFoodName: $foodName")
return testFood.name
}
override suspend fun suspendBuyFood(): Boolean {
Log.d(TAG, "[SERVER] suspendBuyFood")
return true
}
override suspend fun suspendGetFood(): Food {
Log.d(TAG, "[SERVER] suspendGetFood")
return testFood
}
}
- 推荐使用协程的方式调用;
- 自定义的参数中的对象或函数返回值对象不能被混淆;
- 自定义的参数是对象时,该对象必须实现Parcelable接口;
- 接口带有返回值是「同步」调用,不带返回值是「异步」调用;
- 如果项目支持 协程,无论是否带返回值的接口都支持「异步」调用;
- 当接口带有返回值时,调用方需要考虑调用同步方法的时候的线程防止出现ANR(协程不需要考虑);
- 接口如果有返回值,但是如果远程调用失败,返回值为空,请注意「空指针」异常;
-keep class * extends com.softtanck.IRaMessageInterface { *;}
-keep interface * extends com.softtanck.IRaMessageInterface { *;}
-keep class com.softtanck.ramessageclient.core.engine.retrofit.RemoteServiceMethod { *; }
-keep class com.softtanck.ramessageservice.** { *; }
Copyright 2023 Softtanck.
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.