Android开源:AndLinker-Android 上的 IPC 库

GGWBrodie 1年前
   <h2>简介</h2>    <p>AndLinker是一款Android上的IPC (进程间通信) 库,结合了 <a href="/misc/goto?guid=4959715941830775688" rel="nofollow,noindex">AIDL</a> 和 <a href="/misc/goto?guid=4958964956869128717" rel="nofollow,noindex">Retrofit</a> 的诸多特性,且可以与 <a href="/misc/goto?guid=4959757469828583492" rel="nofollow,noindex">RxJava</a> 和 <a href="/misc/goto?guid=4959757469919153667" rel="nofollow,noindex">RxJava2</a> 的Call Adapters无缝结合使用。项目的设计与部分代码参考了伟大的 <a href="/misc/goto?guid=4958964956869128717" rel="nofollow,noindex">Retrofit</a> 项目。</p>    <h2>配置</h2>    <p>在项目根目录的 build.gradle 中添加 jcenter() 仓库</p>    <pre>  <code class="language-java">allprojects {      repositories {          jcenter()      }  }</code></pre>    <p>在App的 build.gradle 中添加如下依赖</p>    <pre>  <code class="language-java">dependencies {      implementation 'com.codezjx.library:andlinker:0.7.0'  }</code></pre>    <h2>功能特性</h2>    <ul>     <li>以普通Java接口代替AIDL接口</li>     <li>像 <a href="/misc/goto?guid=4958964956869128717" rel="nofollow,noindex">Retrofit</a> 一样生成远程服务接口的IPC实现</li>     <li>支持的Call Adapters: Call , <a href="/misc/goto?guid=4959757469828583492" rel="nofollow,noindex">RxJava</a> Observable , <a href="/misc/goto?guid=4959757469919153667" rel="nofollow,noindex">RxJava2</a> Observable & Flowable</li>     <li>支持远程服务回调机制</li>     <li>支持AIDL的所有数据类型</li>     <li>支持AIDL的所有数据定向tag: in , out , inout</li>     <li>支持AIDL的 oneway 关键字</li>    </ul>    <h2>快速开始</h2>    <p>使用注解 @ClassName 和 @MethodName 修饰远程服务接口 IRemoteService ,并实现它</p>    <pre>  <code class="language-java">@ClassName("com.example.andlinker.IRemoteService")  public interface IRemoteService {        @MethodName("getPid")      int getPid();        @MethodName("basicTypes")      void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,              double aDouble, String aString);  }    private final IRemoteService mRemoteService = new IRemoteService() {            @Override      public int getPid() {          return android.os.Process.myPid();      }        @Override      public void basicTypes(int anInt, long aLong, boolean aBoolean,          float aFloat, double aDouble, String aString) {          // Does something      }  };</code></pre>    <p>在服务端App中,创建 AndLinkerBinder 对象,并注册上面的接口实现。然后在 onBind() 方法中返回,暴露给客户端</p>    <pre>  <code class="language-java">private AndLinkerBinder mLinkerBinder;    public class RemoteService extends Service {      @Override      public void onCreate() {          super.onCreate();          mLinkerBinder = AndLinkerBinder.Factory.newBinder();          mLinkerBinder.registerObject(mRemoteService);      }        @Override      public IBinder onBind(Intent intent) {          return mLinkerBinder;      }  }</code></pre>    <p>在客户端App中,通过 Builder 创建 AndLinker 对象,并通过 create() 方法生成一个 IRemoteService 远程接口的IPC实现</p>    <pre>  <code class="language-java">public class BindingActivity extends Activity {        private AndLinker mLinker;      private IRemoteService mRemoteService;        @Override      protected void onCreate(@Nullable Bundle savedInstanceState) {          super.onCreate(savedInstanceState);          mLinker = new AndLinker.Builder(this)                  .packageName("com.example.andlinker")                  .action("com.example.andlinker.REMOTE_SERVICE_ACTION")                  .build();          mLinker.bind();            mRemoteService = mLinker.create(IRemoteService.class);      }        @Override      protected void onDestroy() {          super.onDestroy();          mLinker.unbind();      }  }</code></pre>    <p>一切就绪,现在 mRemoteService 对象中的所有方法都是IPC方法,直接调用即可</p>    <pre>  <code class="language-java">int pid = mRemoteService.getPid();  mRemoteService.basicTypes(1, 2L, true, 3.0f, 4.0d, "str");</code></pre>    <h2>支持数据类型</h2>    <p>AndLinker支持AIDL所有数据类型:</p>    <ul>     <li>Java语言中的所有原始类型 (如: int , long , char , boolean ,等等)</li>     <li>String</li>     <li>CharSequence</li>     <li>Parcelable</li>     <li>List (List中的所有元素必须是此列表中支持的数据类型)</li>     <li>Map (Map中的所有元素必须是此列表中支持的数据类型)</li>    </ul>    <h2>进阶使用</h2>    <h3>Call Adapters</h3>    <p>在客户端App中,你可以copy并修改远程服务接口,包装方法的返回值</p>    <pre>  <code class="language-java">@ClassName("com.example.andlinker.IRemoteService")  public interface IRemoteService {        @MethodName("getPid")      Observable<Integer> getPid();        @MethodName("basicTypes")      Call<Void> basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,           double aDouble, String aString);  }</code></pre>    <p>在 AndLinker.Builder 中注册对应的Call Adapter Factory,剩下的步骤基本和 <a href="/misc/goto?guid=4958964956869128717" rel="nofollow,noindex">Retrofit</a> 一致,不再赘述</p>    <pre>  <code class="language-java">new AndLinker.Builder(this)          ...          .addCallAdapterFactory(OriginalCallAdapterFactory.create()) // Basic          .addCallAdapterFactory(RxJava2CallAdapterFactory.create())  // RxJava2          .build();</code></pre>    <h3>处理远程服务接口回调</h3>    <p>使用 @ClassName 和 @MethodName 注解修饰远程服务回调接口 IRemoteCallback</p>    <pre>  <code class="language-java">@ClassName("com.example.andlinker.IRemoteCallback")  public interface IRemoteCallback {        @MethodName("onValueChange")      void onValueChange(int value);  }</code></pre>    <p>在远程方法中使用 @Callback 注解修饰callback参数</p>    <pre>  <code class="language-java">@MethodName("registerCallback")  void registerCallback(@Callback IRemoteCallback callback);</code></pre>    <p>在客户端App中,实现上面定义的远程服务回调接口 IRemoteCallback ,并且注册到 AndLinker 中,就是这么简单</p>    <pre>  <code class="language-java">private final IRemoteCallback mRemoteCallback = new IRemoteCallback() {      @Override      public void onValueChange(int value) {          // Invoke when server side callback      }  };  mLinker.registerObject(mRemoteCallback);</code></pre>    <h3>指定数据定向tag</h3>    <p>你可以为远程方法的参数指定 @In , @Out ,或者 @Inout 注解,它标记了数据在底层Binder中的流向,跟AIDL中的用法一致</p>    <pre>  <code class="language-java">@MethodName("directionalParamMethod")  void directionalParamMethod(@In KeyEvent event, @Out int[] arr, @Inout Rect rect);</code></pre>    <p>注意:</p>    <ul>     <li>所有非原始类型必须指定数据定向tag: @In , @Out ,或者 @Inout ,用来标记数据的流向。原始类型默认是 @In 类型,并且不能指定其他值。</li>     <li>使用 @Out 或者 @Inout 修饰的Parcelable参数必须实现 SuperParcelable 接口,否则你必须手动添加此方法 public void readFromParcel(Parcel in) 。</li>    </ul>    <h3>使用 @OneWay 注解</h3>    <p>你可以在远程方法上使用 @OneWay 注解,这会修改远程方法调用的行为。当使用它时,远程方法调用不会堵塞,它只是简单的发送数据并立即返回,跟AIDL中的用法一致</p>    <pre>  <code class="language-java">@MethodName("onewayMethod")  @OneWay  void onewayMethod(String msg);</code></pre>    <h2>反馈</h2>    <p>欢迎各位提issues和PRs!</p>    <h2>License</h2>    <pre>  <code class="language-java">Copyright 2018 codezjx <code.zjx@gmail.com>    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.</code></pre>    <p> </p>    <p> </p>