本文主要采用AIDL实现,概念不讲,只说明具体搭建步骤,想了解AIDL的介绍和使用可以参考:
1、Android studio新建项目,创建2个module,一个命名serverApp,一个命名clientApp。
server端配置:
2、server端main目录下创建aidl目录,New->AIDL文件,完成后效果如下:
3、在IMyAidlInterface.aidl创建一个方法测试,如果想使用参数,和java一样,写好后编译一下,生成对应的java文件以便后面使用
interface IMyAidlInterface {
String ipcMsg();
}
4、在java目录创建service实现IMyAidlInterface接口
override fun onBind(intent: Intent): IBinder {
return myBinder
}
private val myBinder = object: IMyAidlInterface.Stub(){
override fun ipcMsg(): String {
return "服务端返回消息"
}
}
5、在AndroidManifest里配置service,android:exported="true",必须配置成true,才能被其他app调用
<service
android:name=".IpcService"
android:enabled="true"
android:exported="true"/>
client端配置:
6、把刚才创建的aidl整个目录内容全拷贝到clientApp相同目录下,不要修改任何内容,同理,后期如果在server端修改了此文件,在client端需要同步一下,同样编译后生成对应java文件:
7、在MainActivity绑定service,注意ComponentName的第一个参数需要和serverApp的applicationId保持一致,第二个参数是service路径,编码过程中,遇到过几种bindService为false的情况,会在后面单独说明。
private val serviceConnection = object : ServiceConnection {
override fun onServiceConnected(p0: ComponentName?, iBinder: IBinder?) {
ipcAidl = IMyAidlInterface.Stub.asInterface(iBinder)
}
override fun onServiceDisconnected(p0: ComponentName?) {
ipcAidl = null
}
}
private fun bindService() {
val mIntent = Intent()
mIntent.component = ComponentName("com.ninjuli.ipc", "com.ninjuli.ipc.IpcService")
bindFlag = bindService(mIntent, serviceConnection, Context.BIND_AUTO_CREATE)
}
8、最后进行测试,先安装serverApp,再安装clientApp,点击按钮,效果如下:
一个简单的跨app通信传递消息完成了,思考:如何传递对象?如何传递超过1M的数据?(为什么1M,去看看binder),会单独开一篇说明
传递对象
1、在serverApp的java目录创建类Person,实现Parcelable,由于这里用的kotlin,简化代码如下
@Parcelize
data class Person(val name: String, val age: Int) : Parcelable
需要在build.gradle配置
plugins {
id 'kotlin-parcelize'
}
2、在aidl目录创建相同Person的aidl文件
import com.ninjuli.ipc.Person;
parcelable Person;
注意这里一定要导入Person的路径,不然会报错
3、在IMyAidlInterface.aidl添加
List<Person> addPerson(in Person person);
完成后编译,把刚才java目录创建的Person类和aidl目录文件同样的拷贝一份到clientApp,名字无需修改。
4、修改IpcService,实现添加的addPerson方法
private val myBinder = object: IMyAidlInterface.Stub(){
override fun ipcMsg(): String {
return "服务端返回消息"
}
override fun addPerson(person: Person): MutableList<Person> {
return mutableListOf(person)
}
}
5、client添加按钮事件
findViewById<Button>(R.id.btn1).setOnClickListener {
val addPerson = ipcAidl?.addPerson(Person("小青", 21))
findViewById<TextView>(R.id.text).text = addPerson?.toString()
}
最终效果
突破binder只能传递小于1M数据,参考下面文章
android多个app跨进程通信(IPC)实现(二)
特别说明编码过程中遇到的问题:
1、bindService总是返回false,百度搜索,会发现很多重复的,我出现的问题都对不上号,最后发现在安卓10以下正常,10以上就出现绑定失败,就得引申出来一个包的可见性,在manifest加上以下配置解决
<queries>
<package android:name="com.ninjuli.ipc" />
</queries>
2、刚开始先安装client,再安装server,就会出现闪退问题,后来发现是在manifest配置service的时候多加了android:permission造成,去掉即可