背景
在学习photo picker文档时,看到了这样一个描述;可以通过一种方法,将另一个进程的复杂页面渲染到当前页面中,并支持做复杂交互,且具备一定的安全性和隐私性保护。结合之前项目上的一个诉求(给第三方业务暴露登陆按钮,但不想让业务方得知实现细节,避免业务方后台调用该按钮后台偷偷登陆)感觉可以用这种方式去实现,因此去了解下细节

实现效果

实现方式:
1、使用SurfaceControlViewHost + SurfaceView 实现
SurfaceView原理: 核心是把主进程的surface传递给单独的渲染进程,从而实现跨进程渲染的效果
SurfaceControlViewHost: 并提供将渲染进程的view嵌入到主进程中


使用步骤
客户端(主进程):
--创建用于展示内容的,surfaceView,提供host token确定是具体哪个surface View,提供display ID,用于渲染的一些基础依赖(字体大小等)
--获取服务端返回的SurfacePackage,与surfaceView绑定
--事件通知,所有input事件,通知服务器
服务端(渲染进程):
--使用客户端提供的display ID、hostToken 创建SurfaceControlViewHost,创建自定义view,返回SurfacePackage给客户端
--接收input事件,传递给自定义view

java
//aidl
interface IRemoteRender {
//客户端提供surface、大小、display 从服务端获取 surfacePackage
SurfacePackage getSurfacePackage(int displayId, IBinder hostToken, int width, int height);
//客户端向服务端传递 事件
boolean onTouch(in MotionEvent motionEvent);
}
//服务端
private final IRemoteRender.Stub mBinder = new IRemoteRender.Stub() {
@Override
public SurfaceControlViewHost.SurfacePackage getSurfacePackage(int displayId, IBinder hostToken, int width, int height) {
Log.i(TAG, "getSurfacePackage, displayId=" + displayId + ", hostToken=" + hostToken + ", width=" + width + ", height=" + height);
final SurfaceControlViewHost.SurfacePackage[] result = new SurfaceControlViewHost.SurfacePackage[1];
final CountDownLatch latch = new CountDownLatch(1);
mHandler.post(new Runnable() {
@Override
public void run() {
// 创建SurfaceControlViewHost
Context context = getBaseContext();
Display display = context.getSystemService(DisplayManager.class).getDisplay(displayId);
mSurfaceControlViewHost = new SurfaceControlViewHost(context, display, hostToken);
createRootView(width,height);
// 将视图附加到SurfaceControlViewHost
mSurfaceControlViewHost.setView(mRootView, width, height);
result[0] = mSurfaceControlViewHost.getSurfacePackage();
latch.countDown();
}
});
try {
latch.await(); // 等待主线程完成操作
return result[0];
} catch (InterruptedException e) {
Log.i(TAG, "getSurfacePackage, e=" + e.getMessage());
}
return null;
}
@Override
public boolean onTouch(MotionEvent event) throws RemoteException {
final CountDownLatch latch = new CountDownLatch(1);
final boolean[] result = {true};
mHandler.post(new Runnable() {
@Override
public void run() {
mRootView.dispatchTouchEvent(event);
latch.countDown();
}
});
try {
latch.await(); // 等待主线程完成操作
return result[0];
} catch (InterruptedException e) {
Log.i(TAG, "getSurfacePackage, e=" + e.getMessage());
}
return true;
}
};
//客户端
try {
IBinder hostToken = mSurfaceView.getHostToken();
SurfaceControlViewHost.SurfacePackage surfacePackage = mRemoteRender.getSurfacePackage(0, hostToken, 1000, 2000);
mSurfaceView.setChildSurfacePackage(surfacePackage);
mSurfaceView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
try {
return mRemoteRender.onTouch(motionEvent);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
}
});
} catch (RemoteException e) {
e.printStackTrace();
}