zoukankan      html  css  js  c++  java
  • Android 通过AIDL在两个APP之间Service通信

    一、项目介绍

    【知识准备】

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

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

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

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

     

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

    【项目结构】

      

     

    【MyService】

    【提示】

      ①创建Service

      

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

    1 <service
    2             android:name=".MyService"
    3             android:enabled="true"
    4             android:exported="true"></service>

    【代码】

     1 public class MyService extends Service {
     2     public MyService() {
     3     }
     4 
     5     @Override
     6     public IBinder onBind(Intent intent) {
     7         return new MyBinder();//return MyBinder通过ServiceConnection在activity中拿到MyBinder
     8     }
     9 
    10     @Override
    11     public int onStartCommand(Intent intent, int flags, int startId) {
    12 
    13         return super.onStartCommand(intent, flags, startId);
    14     }
    15 
    16     public  void  payService(){
    17         Log.i("MyService", "payService: --------");
    18     }
    19 
    20     class MyBinder extends Binder{
    21 
    22         public void pay(){
    23             payService();
    24         }//通过Binder实例将service中的方法暴露出去
    25     }
    26 }

    【layout_main】

          添加按钮,点击便于调用

    1     <Button
    2         android:id="@+id/btn_paly"
    3         android:text="Pay"
    4         android:layout_width="wrap_content"
    5         android:layout_height="wrap_content" />

    【MainActivity】

     1 public class MainActivity extends AppCompatActivity {
     2 
     3     MyService.MyBinder binder = null;
     4     ServiceConnection conn;
     5 
     6     @Override
     7     protected void onCreate(Bundle savedInstanceState) {
     8         super.onCreate(savedInstanceState);
     9         setContentView(R.layout.activity_main);
    10 
    11         Button btnPlay = (Button) findViewById(R.id.btn_paly);
    12         conn = new ServiceConnection() {
    13             @Override
    14             public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
    15                 binder = (MyService.MyBinder) iBinder;
    16             }
    17 
    18             @Override
    19             public void onServiceDisconnected(ComponentName componentName) {
    20 
    21             }
    22         };
    23 
    24         Intent intent = new Intent(MainActivity.this,MyService.class);
    25         bindService(intent,conn,BIND_AUTO_CREATE);//开启服务
    26 
    27         btnPlay.setOnClickListener(new View.OnClickListener() {
    28             @Override
    29             public void onClick(View view) {
    30                 if (binder!=null){
    31                     binder.play();
    32                 }
    33             }
    34         });
    35     }
    36 }

    【效果】

      

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

      

     

     三、两个App之间的Service通信

    【项目结构】

      

     

    【步骤】

    ①在AppPayProvider中创建MyService

      代码同上

    【注册】

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

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

     1         <service
     2             android:name=".MyService"
     3             android:enabled="true"
     4             android:exported="true">
     5             <!--enable:ture设置可用
     6             exported:ture对外暴露 -->
     7             <intent-filter>
     8                 <action android:name="com.xqz.apppayprovider.MyService" />
     9             </intent-filter>
    10         </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】

    1     <Button
    2         android:id="@+id/btnPay"
    3         android:text="pay"
    4         android:layout_width="wrap_content"
    5         android:layout_height="wrap_content" />

     

    ⑦将AppPayProvider中AIDL拷贝到AppPayUser中

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

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

      

     

    ⑧【AppPayUser-MainActivity】

     1 public class MainActivity extends AppCompatActivity {
     2 
     3     Button btnPay;
     4     private IPay myBinder;//定义AIDL
     5 
     6     ServiceConnection conn = new ServiceConnection() {
     7         @Override
     8         public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
     9 
    10             myBinder = IPay.Stub.asInterface(iBinder);
    11         }
    12 
    13         @Override
    14         public void onServiceDisconnected(ComponentName componentName) {
    15 
    16         }
    17     };
    18 
    19     @Override
    20     protected void onCreate(Bundle savedInstanceState) {
    21         super.onCreate(savedInstanceState);
    22         setContentView(R.layout.activity_main);
    23 
    24         Intent intent = new Intent();
    25         intent.setAction("com.xqz.apppayprovider.MyService");
    26         //表示按照什么进行过滤,启动意图
    27         /*android5.0之后,如果servicer不在同一个App的包中,
    28          需要设置service所在程序的包名
    29          (包名可以到App的清单文件AndroidManifest中查看)*/
    30         intent.setPackage("com.xqz.apppayprovider");
    31         bindService(intent,conn,BIND_AUTO_CREATE);//开启Service
    32 
    33         btnPay = (Button) findViewById(R.id.btnPay);
    34 
    35         btnPay.setOnClickListener(new View.OnClickListener() {
    36             @Override
    37             public void onClick(View view) {
    38                 try {
    39                     myBinder.pay();
    40                 } catch (RemoteException e) {
    41                     //因为是跨程序调用服务,可能会出现远程异常
    42                     e.printStackTrace();
    43                 }
    44             }
    45         });
    46     }
    47 }

     

    【安装】

      先安装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不需要。

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

     

    五、园友实践问题

    1、Attempt to invoke interface method 'void com.example.aidl_.IPsy.pay()' on a null object  

      

     错误原因:提供远程服务的应用和调用远程服务的应用不是同一个应用,两个应用使用的applicationId 相同。要想在同一个手机上安装,他们得设置不同的 applicationId (buidle.gradle)

    有关ApplicationId:applicationId默认为应用的包名,可以修改,也有相应的命名规则。bindService intent 设置 setPackage 这里不是字面上的应用包名,而是应用的 ApplicationId,这也会导致 bindService 返回 false 更多请参考博客:Gradle学习之设置applicationId( https://www.jianshu.com/p/4653c8a38771

     

     

     

    2、api 30 Android 11  bindservice 返回 false,在 API 28 (Android 9)的模拟器上是可以的 bindService 返回 true,但是运行到 API 30(Android 11)上就返回 false。

      我刚开始解决问题的方向一直放在代码上面,是为了兼容需要在代码上做什么处理,看了官网并没有得到什么信息。

      园友说将 targetSDKVersion 设置为 28就可以了。

      targetSDKVersion 设置应用的目标版本,当Android版本低于APP的目标的API时,将使用Android手机版本API即28,当APP目标版本低于Android手机版本,将以APP目标版本API在Android手机上以目标版本的行为运行,也就是 目标版本设置为 28 在api30 的手机上,以api 28行为运行,这也就是APP的向上兼容。

     

  • 相关阅读:
    IOException while loading persisted sessions:java.io.EOFException
    Android Studio | 详细安装教程
    Android -- 关闭AsyncTask(异步任务)
    钢铁侠传-文言文
    http协议 get/post 请求 解析XML
    HTTP状态码大全
    jquery+ajax 类百度输入框
    这就是知识点
    关于Eclipse+SVN 开发配置
    企业信息化快速开发平台--JeeSite
  • 原文地址:https://www.cnblogs.com/xqz0618/p/aidl_service.html
Copyright © 2011-2022 走看看