preface
WebView same-layer rendering is not a new technology. First-line Internet products in China are widely used, such as native components of small programs, and scenes of native players embedded in e-commerce H5.
Scenario analysis | Technology blog |
---|---|
Wechat applets | Small procedures of the same layer render principle analysis |
Baidu applet | [Into the small program principle] reveal the components of the same layer rendering |
Taobao system player | 618 Amoy front-end technology sharing |
If you understand how this works, you will find that it is difficult to get started on Android because you need to modify the browser kernel. After reading the article, I called it awesome, but I looked back at the native WebView code and couldn’t find the right API.
Introduction to same layer rendering
On the Android platform, H5 content relies on WebView rendering, which has an independent and equal relationship with the native View. From the perspective of drawing level, WebView and native are bound to cover each other, not to do synchronous scrolling;
In the web DOM tree, some native components are intermingled, and the original layers and styles are retained. This is called same-layer rendering.
What problems can same-layer rendering solve?
The use of Web front-end technology is difficult to achieve, or stability, performance limitations
For example: video player, map, game engine, live push and pull stream, camera preview and other scenes;
See X5 kernel browser same-layer rendering
Preparations:
- Access Tencent X5 browser x5.tencent.com/ correctly
- Ensure the X5 kernel loaded x5.tencent.com/docs/questi success…
Prepare a placeholder label
The principle of X5 same-layer rendering is to use native to take over specific tags in H5 pages, so prepare an H5 page and insert a custom tag. The name of the tag can be arbitrarily defined, such as MyTag, and the style is set according to standard CSS
<mytag id = "mytag" src="https://vfx.mtime.cn/Video/2019/02/04/mp4/190204084208765161.mp4" style="position:absolute; width:350px; height:500px;" > placeholder tag </mytag>Copy the code
Force X5WebView same-layer rendering on
X5 same layer rendering capability is off by default, through the cloud switch control, through analysis found that you can force modification of local SP properties, forced open
if (mWebView.getX5WebViewExtension()! Enable SharedPreferences TBs_public_settings = getSharedPreferences(" TBs_public_settings ", Context.MODE_PRIVATE); SharedPreferences.Editor edit = tbs_public_settings.edit(); edit.putInt("MTT_CORE_EMBEDDED_WIDGET_ENABLE",1); edit.apply(); }else {log.d (TAG, "init: non-X5 kernel "); }Copy the code
Native control that registers the target placeholder tag with the browser
Using the registerEmbeddedWidget method, you can register placeholders with the browser kernel that need native tags to take over. The first parameter is the name of the tag to take over. The second parameter is the factory interface that the factory creates for the native tag object
// Register placeholder tags in the DOM tree, Create the corresponding native components Boolean result = mWebView. GetX5WebViewExtension () registerEmbeddedWidget (new String [] {} "mytag", new IEmbeddedWidgetClientFactory() { @Override public IEmbeddedWidgetClient createWidgetClient(String s, Map<String, String> map, IEmbeddedWidget iEmbeddedWidget) { Log.d(TAG, "init: createWidgetClient s"+s); Log.d(TAG, "init: createWidgetClient map"+map.toString()); return new VideoEmbeddedWidgetClient(BrowserActivity.this); }});Copy the code
CreateWidgetClient method parameter meaning
s
Label name, uppercasemap
Attribute of the tag, specified in HTMLiEmbeddedWidget
Provides a native proxy interface for this label
Here is what map prints
init: createWidgetClient map{src=https://vfx.mtime.cn/Video/2019/02/04/mp4/190204084208765161.mp4, style=position:absolute; width:350px; height:500px; , id=mytag}Copy the code
An implementation that handles native placeholder controls, IEmbeddedWidgetClient
How does the native take over replacement placeholder tags, the main implementation class being IEmbeddedWidgetClient
public interface IEmbeddedWidgetClient {
void onSurfaceCreated(Surface var1);
void onSurfaceDestroyed(Surface var1);
boolean onTouchEvent(MotionEvent var1);
void onRectChanged(Rect var1);
void onVisibilityChanged(boolean var1);
void onDestroy();
void onActive();
void onDeactive();
void onRequestRedraw();
}
Copy the code
First, the IEmbeddedWidgetClient is not a native View, but rather provides the native drawing entry for the tag area, understood from onSurfaceCreated and onSurfaceDestroyed;
Since it is not a native View drawing, X5 still provides attributes that resemble views, which can be easily seen from the API naming.
onSurfaceCreated
This label can be drawn, requesting native API processingonSurfaceDestroyed
The label view is destroyed, requesting native destructiononTouchEvent
Touch event distributiononRectChanged
The label is called back to coordinate changes in the WebView (e.g. scrolling, changing width and height)onVisibilityChanged
The label shows hiddenonDestroy
The label is removed, or display = None
Demonstrate a Demo
Familiar with X5 API, write a simple Demo to play
The design idea of Demo is to embed a native camera in a vertical scrolling web page. The native camera should be collected and displayed normally, and the front-end code can control the basic operations of camera label display and hiding, synchronous scrolling and so on.
Web page
<! DOCTYPE HTML > < HTML > <head> <title> <meta charset=" utF-8 "> <meta Content ="width=device-width, Initial - scale = 1.0, the maximum - scale = 1.0, user - scalable = no, shrink-to-fit=no" name="viewport"> <script type="text/javascript"> window.onload = touchtouch; function touchtouch(){ var camera = document.getElementById('camera'); console.log("camera:"+camera) camera.addEventListener("touchStart",handlerTouch,false); camera.addEventListener("touchend",handlerTouch,false); camera.addEventListener("touchcancel",handlerTouch,false); camera.addEventListener("touchleave",handlerTouch,false); camera.addEventListener("touchmove",handlerTouch,false); } function handlerTouch(evt){ log(evt); } </script> </head> <body> <p> <div style="background-color: aqua; height: 100px; text-align: center;" >1</div> <div style="background-color: gray; height: 100px; text-align: center;" >2</div> <div style="background-color: rgb(80, 69, 69); height:500px;" > <camera cameraId=0 style="position:absolute; width:350px; height:500px;" </camera> <a href="https://www.baidu.com" style="position:absolute; </a> <div style="background-color: gold; background-color: gold; height: 100px; text-align: center;" >4</div> <div style="background-color: red; height: 100px; text-align: center;" >5</div> <div style="background-color: green; height: 100px; text-align: center;" >6</div> </div> </body> </html>Copy the code
Java implementation
public class CameraEmbeddedWidgetClient implements IEmbeddedWidgetClient { private String TAG = "VideoEmbeddedWidgetClient"; private Rect rect; private CameraHelper cameraHelper; public CameraEmbeddedWidgetClient(Context c) { cameraHelper = new CameraHelper(c); } @Override public void onSurfaceCreated(Surface surface) { Log.d(TAG, "onSurfaceCreated: "); // Canvas canvas = surface.lockCanvas(rect); // canvas.drawColor(Color.parseColor("#7f000000")); // surface.unlockCanvasAndPost(canvas); cameraHelper.preview(surface); } @Override public void onSurfaceDestroyed(Surface surface) { Log.d(TAG, "onSurfaceDestroyed: "); cameraHelper.release(); }}Copy the code
Front-end style changes and Native event firing
Specify the style display: None
Native callbackonVisibilityChanged(false)
andonDestroy
Specifies the style display:block
Create a new ClientSpecify style visibility:visible
Native callbackonVisibilityChanged(true)
Specify style visibility:hidden
Native callbackonVisibilityChanged(false)
Remove the current DOM
Equivalent to display: none
Validation of touch events
You must set up a tag change event listener in JS
camera.addEventListener("touchStart",handlerTouch,false);
camera.addEventListener("touchend",handlerTouch,false);
camera.addEventListener("touchcancel",handlerTouch,false);
camera.addEventListener("touchleave",handlerTouch,false);
camera.addEventListener("touchmove",handlerTouch,false);
Copy the code
Natively accept event handling
IEmbeddedWidgetClient implementation class
@Override public boolean onTouchEvent(MotionEvent motionEvent) { Log.d(TAG, "onTouchEvent: "+motionEvent.toString()); float x = motionEvent.getX(); float y = motionEvent.getY(); int action = motionEvent.getAction(); switch (action){ case MotionEvent.ACTION_DOWN: initX = x; initY = y; intercepted = false; return false; case MotionEvent.ACTION_MOVE: float dx = x - initX; float dy = y - initY; if (! intercepted && Math.abs(dy)>Math.abs(dx) && Math.abs(dy)>16){ intercepted = true; } break; case MotionEvent.ACTION_UP: break; } return intercepted; }Copy the code
conclusion
This article mainly shares the X5 kernel hidden layer rendering ability, used for learning and communication, but there is no official documentation, so please be cautious about introducing projects; If you’re interested in this topic, try it yourself.