当前位置: 首页 > 编程笔记 >

Android通过AIDL在两个APP之间Service通信

吕修伟
2023-03-14
本文向大家介绍Android通过AIDL在两个APP之间Service通信,包括了Android通过AIDL在两个APP之间Service通信的使用技巧和注意事项,需要的朋友参考一下

一、项目介绍

【知识准备】

  ①Android Interface definition language(aidl,android接口定义语言),其目的实现跨进程的调用。进程是程序在os中执行的载体,一个程序对应一个进程,不同进程就是指不同程序,aidl实现不同程序之间的调用。

  ②主线程与子线程通信使用handler,handler可以在子线程中发出消息,在主线程处理消息,从而完成线程之间的通信,即使有多个线程,仍然是一个程序。

  ③不同程序之间需要通过aidl通信,通信方式可以有多种,aidl是其中一种。实现的结果就像自己的程序调用自己的其他方法一样,感觉就像一个程序。

  ④业务场景:例如购物app需要支付,购物app是淘宝,支付app是支付宝。所以就需要不同的程序进行通信。 

二、首先介绍一个App之间的Service和Activity之间的通信

【项目结构】  

【MyService】

【提示】

  ①创建Service

   ②如果不是通过上述方法创建,一定要记得注册

 <service
 android:name=".MyService"
 android:enabled="true"
 android:exported="true">

</service>

【代码】

public class MyService extends Service {
 public MyService() {
 }

 @Override
 public IBinder onBind(Intent intent) {
 return new MyBinder();//return MyBinder通过ServiceConnection在activity中拿到MyBinder
 }

 @Override
 public int onStartCommand(Intent intent, int flags, int startId) {

 return super.onStartCommand(intent, flags, startId);
 }

 public void payService(){
 Log.i("MyService", "payService: --------");
 }

 class MyBinder extends Binder{

 public void pay(){
 payService();
 }//通过Binder实例将service中的方法暴露出去
 }
}

【layout_main】

添加按钮,点击便于调用

<Button
 android:id="@+id/btn_paly"

 android:text="Pay"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content" />

【MainActivity】

public class MainActivity extends AppCompatActivity {

 MyService.MyBinder binder = null;
 ServiceConnection conn;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);

 Button btnPlay = (Button) findViewById(R.id.btn_paly);
 conn = new ServiceConnection() {
 @Override
 public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
 binder = (MyService.MyBinder) iBinder;
 }

 @Override
 public void onServiceDisconnected(ComponentName componentName) {

 }
 };

 Intent intent = new Intent(MainActivity.this,MyService.class);
 bindService(intent,conn,BIND_AUTO_CREATE);//开启服务

 btnPlay.setOnClickListener(new View.OnClickListener() {
 @Override
 public void onClick(View view) {
 if (binder!=null){
  binder.play();
 }
 }
 });
 }
}

【效果】

点击后输出service中pay方法中的内容

 三、两个App之间的Service通信

【项目结构】

【步骤】

①在AppPayProvider中创建MyService

代码同上

【注册】

  Ⅰ、注册时(android:enabled="true"   android:exported="true" )设置为true,将Service暴露出去,另一个App才能访问到它

  Ⅱ、添加『 <intent-filter> 』。由于不是同一个App,通过intent-filter对Intent进行过滤,让另一个app通过action开启服务

<service
 android:name=".MyService"
 android:enabled="true"
 android:exported="true">
 <!--enable:ture设置可用
 exported:ture对外暴露 -->
 <intent-filter>
 <action android:name="com.xqz.apppayprovider.MyService" />
 </intent-filter>
</service> 

②MainActivity和layout_main保留创建时不作任何修改,但也不要删掉,因为安装程序必须提供起始页面,否则将会出错

③在AppPayProvider中添加AIDL

【代码】  

【提示】接口中定义中方法要和Service中的MyBinder中的方法一致

④再创建好AIDL,添加完方法后,android studio需要对这个aidl进行编译,会自动按aidl规范生成一个Binder子类的代码。

⑤对MyService中的MyBinder进行修改

【提示】继承IPay.Stub。在这之前必须Make Project,否则将没有只能联想

⑥创建AppPayUser对AppPayProvider中的MyService进行操作

【layout-main】

 <Button
 android:id="@+id/btnPay"
 android:text="pay"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content" /> 

⑦将AppPayProvider中AIDL拷贝到AppPayUser中

【提示】Ⅰ、包名要相同,按目录位置复制,通过下述方法,直接在文件夹进行复制。『此处可以查看项目结构,可以看到包名是相同的』

    Ⅱ、同样拷贝过来后需要Make Project   

⑧【AppPayUser-MainActivity】

public class MainActivity extends AppCompatActivity {

 Button btnPay;
 private IPay myBinder;//定义AIDL

 ServiceConnection conn = new ServiceConnection() {
 @Override
 public void onServiceConnected(ComponentName componentName, IBinder iBinder) {

 myBinder = IPay.Stub.asInterface(iBinder);
 }

 @Override
 public void onServiceDisconnected(ComponentName componentName) {

 }
 };

 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);

 Intent intent = new Intent();
 intent.setAction("com.xqz.apppayprovider.MyService");
 //表示按照什么进行过滤,启动意图
 /*android5.0之后,如果servicer不在同一个App的包中,
 需要设置service所在程序的包名
 (包名可以到App的清单文件AndroidManifest中查看)*/
 intent.setPackage("com.xqz.apppayprovider");
 bindService(intent,conn,BIND_AUTO_CREATE);//开启Service

 btnPay = (Button) findViewById(R.id.btnPay);

 btnPay.setOnClickListener(new View.OnClickListener() {
 @Override
 public void onClick(View view) {
 try {
  myBinder.pay();
 } catch (RemoteException e) {
  //因为是跨程序调用服务,可能会出现远程异常
  e.printStackTrace();
 }
 }
 });
 }
}

【安装】

  先安装AppPayProvider再安装AppPayUser。

【效果】

  将run中的 视图调到AppPayProvider,点击模拟器AppPayUser中的pay按钮,将会执行AppPayProvider中MyService中pay方法中的内容。

四、总结

【跨App和同App之间的区别】
①跨App开启服务是提供服务的App需要设置intent-filter过滤器,控制服务的App需要通过。setAction和setPackage方法进行设置action和包名,才能开启服务。而同App只需要指定启动的service就可。

②跨App的MyBinder实例要通过AIDL获取,两个应用定义同样的接口的方法,通过对应的AIDL名称.Stub.asInterface方法得到binder实例,然后就和同App的myBinder使用么有区别了。

③跨App的MyBinder对象的使用必须捕获异常,而同App不需要。

④可以根据上方简单的例子实现很多类似的功能。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小牛知识库。

 类似资料:
  • 问题内容: 我的机器在窗口7上运行。我想 在同一机器上运行的两个android仿真器之间进行通信。 仿真器第一个正在侦听某些IP 10.0.2.15,第二个仿真器尝试 创建IP 它给出了异常,无法连接到10.0.2.15,有人知道如何 解决此问题吗? 编辑:我已经读过 https://developer.android.com/studio/run/emulator-networking#conn

  • 关于基于代理的模型,我有一个问题。 我建立了两个代理。一个有状态图。我希望状态图能够通过发送消息或其他方式被其他代理使用。 我该怎么做?

  • 本文向大家介绍Android 进程间通信AIDL使用详解,包括了Android 进程间通信AIDL使用详解的使用技巧和注意事项,需要的朋友参考一下 一、概述 AIDL 意思即 Android Interface Definition Language,翻译过来就是Android接口定义语言,是用于定义服务器和客户端通信接口的一种描述语言,可以拿来生成用于IPC的代码。从某种意义上说AIDL其实是一

  • 问题内容: 方法论问题: 我有一个“主” python脚本,该脚本在系统上无限循环地运行,并且我想偶尔与其他一些python脚本一起向其发送信息(例如,json数据字符串),这些脚本稍后将由本人或另一个程序启动并且将在发送字符串后立即结束。 我不能在这里使用子流程,因为我的主脚本不知道其他脚本何时运行以及它们将执行什么代码。 我正在考虑使主脚本在本地端口上侦听,并使其他脚本在该端口上向它发送字符串

  • 我有一个Minecraft服务器,它被配置为根据游戏中发生的事件更改我的LED灯条的颜色,但是,此服务器仅在我的计算机上运行时才起作用。这是因为它需要使用Arduino来控制LED灯条。 我想知道是否有任何方法可以通过两个不同的jar文件进行通信,这样当Minecraft中发生事件时,它就会通过一个完全不同的文件告诉我的计算机。 例如:我使用像Server.pro这样的《我的世界》服务器托管商。每

  • 我有两个项目,一个是aspnet核心API项目,另一个是xUnit e2e项目,两者都部署在两个不同的容器中。 一旦两个容器都启动并运行,e2e容器就会尝试在url上访问Web API项目的APIhttps://web-api-container:5010/.但e2e项目无法实现API项目。似乎无法使用其主机名访问API项目(http://web-api-container:5010/). 我的c