2.Aidl相关属性介绍php
3.实际开发中案例操做java
4.可能出现的问题android
5.部分源码解析git
在AIDL中,并不是支持全部数据类型,他支持的数据类型以下所示:github
2.2.1 服务端segmentfault
2.2.2 客户端服务器
3.2.1 服务端app
3.2.2 客户端ide
3.3.1 建立一个aidl文件【注意:在main路径下建立】工具
// ICheckAppInfoManager.aidl package cn.ycbjie.ycaudioplayer; import cn.ycbjie.ycaudioplayer.AppInfo; // Declare any non-default types here with import statements interface ICheckAppInfoManager { //获取app信息,好比token,版本号,签名,渠道等信息 List<AppInfo> getAppInfo(String sign); boolean setToken(String sign,String token); boolean setChannel(String sign,String channel); boolean setAppAuthorName(String sign,String name); }
3.3.2 建立一个AppInfo类,实现Parcelable接口
import android.os.Parcel; import android.os.Parcelable; public class AppInfo implements Parcelable { private String key; private String value; public AppInfo(String key, String value) { this.key = key; this.value = value; } public String getKey() { return key; } public void setKey(String key) { this.key = key; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(this.key); dest.writeString(this.value); } public AppInfo() { } protected AppInfo(Parcel in) { this.key = in.readString(); this.value = in.readString(); } public static final Creator<AppInfo> CREATOR = new Creator<AppInfo>() { @Override public AppInfo createFromParcel(Parcel source) { return new AppInfo(source); } @Override public AppInfo[] newArray(int size) { return new AppInfo[size]; } }; @Override public String toString() { return "AppInfo{" + "key='" + key + '\'' + ", value='" + value + '\'' + '}'; } }
3.3.3 在Service子类中实现AIDL中定义的接口方法,并定义生命周期的方法(onCreat、onBind()等)
/** * <pre> * @author yangchong * blog : * time : 2018/05/30 * desc : 用于aidl多进程通讯服务service * revise: * </pre> */ public class AppInfoService extends Service { @Nullable @Override public IBinder onBind(Intent intent) { LogUtils.i("AppInfoService--IBinder:"); return binder; } @Override public void onCreate() { super.onCreate(); LogUtils.i("AppInfoService--onCreate:"); } @Override public void onDestroy() { super.onDestroy(); LogUtils.i("AppInfoService--onDestroy:"); } /** * 1.核心,Stub里面的方法运行的binder池中。 * 2.Stub类并不是咱们本身建立的,而是AIDL自动生成的。 * 系统会为每一个AIDL接口在build/generated/source/aidl下生成一个文件夹,它的名称跟你命名的AIDL文件夹同样 * 3.Stub类,是一个内部类,他本质上是一个Binder类。当服务端和客户端位于同一个进程时,方法调用不会走跨进程的transact过程, * 当二者处于不一样晋城市,方法调用走transact过程,这个逻辑由Stub的内部代理类Proxy完成。 */ private final IBinder binder = new ICheckAppInfoManager.Stub() { @Override public List<AppInfo> getAppInfo(String sign) throws RemoteException { List<AppInfo> list=new ArrayList<>(); String aidlCheckAppInfoSign = AppToolUtils.getAidlCheckAppInfoSign(); LogUtils.e("AppInfoService--AppInfoService",aidlCheckAppInfoSign+"-------------"+sign); if(!aidlCheckAppInfoSign.equals(sign)){ return list; } list.add(new AppInfo("app版本号(versionName)", BuildConfig.VERSION_NAME)); list.add(new AppInfo("app版本名称(versionCode)", BuildConfig.VERSION_CODE+"")); list.add(new AppInfo("打包时间", BuildConfig.BUILD_TIME)); list.add(new AppInfo("app包名", getPackageName())); list.add(new AppInfo("app做者", SPUtils.getInstance(Constant.SP_NAME).getString("name","杨充"))); list.add(new AppInfo("app渠道", SPUtils.getInstance(Constant.SP_NAME).getString("channel"))); list.add(new AppInfo("token", SPUtils.getInstance(Constant.SP_NAME).getString("token"))); list.add(new AppInfo("App签名", AppToolUtils.getSingInfo(getApplicationContext(), getPackageName(), AppToolUtils.SHA1))); return list; } @Override public boolean setToken(String sign, String token) throws RemoteException { if(!AppToolUtils.getAidlCheckAppInfoSign().equals(sign)){ return false; } SPUtils.getInstance(Constant.SP_NAME).put("token",token); LogUtils.i("AppInfoService--setToken:"+ token); return true; } @Override public boolean setChannel(String sign, String channel) throws RemoteException { if(!AppToolUtils.getAidlCheckAppInfoSign().equals(sign)){ return false; } SPUtils.getInstance(Constant.SP_NAME).put("channel",channel); LogUtils.i("AppInfoService--setChannel:"+ channel); return true; } @Override public boolean setAppAuthorName(String sign, String name) throws RemoteException { if(!AppToolUtils.getAidlCheckAppInfoSign().equals(sign)){ return false; } SPUtils.getInstance(Constant.SP_NAME).put("name",name); LogUtils.i("AppInfoService--setAppAuthorName:"+ name); return true; } }; }
3.3.4 在AndroidMainfest.xml中注册服务 & 声明为远程服务
<service android:name=".service.AppInfoService" android:process=":remote" android:exported="true"> <intent-filter> <action android:name="cn.ycbjie.ycaudioplayer.service.aidl.AppInfoService"/> <category android:name="android.intent.category.DEFAULT"/> </intent-filter> </service>
3.4.1 拷贝服务端的AIDL文件到目录下
3.4.2 经过Intent指定服务端的服务名称和所在包,绑定远程Service
/** * 跨进程绑定服务 */ private void attemptToBindService() { Intent intent = new Intent(); //经过Intent指定服务端的服务名称和所在包,与远程Service进行绑定 //参数与服务器端的action要一致,即"服务器包名.aidl接口文件名" intent.setAction("cn.ycbjie.ycaudioplayer.service.aidl.AppInfoService"); //Android5.0后没法只经过隐式Intent绑定远程Service //须要经过setPackage()方法指定包名 intent.setPackage(packName); //绑定服务,传入intent和ServiceConnection对象 bindService(intent, connection, Context.BIND_AUTO_CREATE); } /** * 建立ServiceConnection的匿名类 */ private ServiceConnection connection = new ServiceConnection() { //重写onServiceConnected()方法和onServiceDisconnected()方法 // 在Activity与Service创建关联和解除关联的时候调用 @Override public void onServiceDisconnected(ComponentName name) { Log.e(getLocalClassName(), "没法绑定aidlServer的AIDLService服务"); mBound = false; } //在Activity与Service创建关联时调用 @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.e(getLocalClassName(), "完成绑定aidlServer的AIDLService服务"); //使用IAppInfoManager.Stub.asInterface()方法获取服务器端返回的IBinder对象 //将IBinder对象传换成了mAIDL_Service接口对象 messageCenter = ICheckAppInfoManager.Stub.asInterface(service); mBound = true; if (messageCenter != null) { try { //连接成功 Toast.makeText(MainActivity.this,"连接成功",Toast.LENGTH_SHORT).show(); } catch (Exception e) { e.printStackTrace(); } } } };
3.4.3 使用Stub.asInterface接口获取服务器的Binder,根据须要调用服务提供的接口方法
private void getAppInfo() { //若是与服务端的链接处于未链接状态,则尝试链接 if (!mBound) { attemptToBindService(); Toast.makeText(this, "当前与服务端处于未链接状态,正在尝试重连,请稍后再试", Toast.LENGTH_SHORT).show(); return; } if (messageCenter == null) { return; } try { List<AppInfo> info = messageCenter.getAppInfo(Utils.getSign(packName)); if(info==null || (info.size()==0)){ Toast.makeText(this, "没法获取数据,多是签名错误!", Toast.LENGTH_SHORT).show(); }else { mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); FirstAdapter adapter = new FirstAdapter(info, this); mRecyclerView.setAdapter(adapter); adapter.setOnItemClickListener(new FirstAdapter.OnItemClickListener() { @Override public void onItemClick(View view, int position) { } }); } } catch (RemoteException e) { e.printStackTrace(); } }
最后看看经过测试工具[客户端]跨进程获取服务端app信息截图
// 在建立ServiceConnection的匿名类中的onServiceConnected方法中 // 设置死亡代理 messageCenter.asBinder().linkToDeath(deathRecipient, 0); /** * 给binder设置死亡代理 */ private IBinder.DeathRecipient deathRecipient = new IBinder.DeathRecipient() { @Override public void binderDied() { if(messageCenter == null){ return; } messageCenter.asBinder().unlinkToDeath(deathRecipient, 0); messageCenter = null; //这里从新绑定服务 attemptToBindService(); } };
<!--给aidl多进程通讯,服务加入权限验证功能--> <permission android:name="aidl.AppInfoService" android:protectionLevel="normal"/> //在AppInfoService服务中验证权限 @Nullable @Override public IBinder onBind(Intent intent) { LogUtils.i("AppInfoService--IBinder:"); int check = checkCallingOrSelfPermission("aidl.AppInfoService"); if(check == PackageManager.PERMISSION_DENIED){ return null; } return binder; }
5.1.2 分析生成的java文件