“Android” detailed and comprehensive access process based on vue2.0weex (Android perspective)

Time:2020-1-17

This article is from Lu Fei, the Android team of Shangzhuang
Published in GitHub blog, welcome to subscribe!

1、 Say what’s in front of you

At present, weex has launched a common order management page on Daren store app under makeup. So far, no problems have been found on Android, and the rendering time is between 100-300ms.

As the development of Android, this paper will first record the access process from the perspective of Android, hoping to provide a little help for the students who are not connected to access weex more conveniently and time-saving. It will involvePreloadingDowngradeHot updateBurying pointAnd when the app is not updatedDynamically configure new pagesAnd so on. These Android and IOS are unified logic. I hope to communicate with you. For the front-end, please refer to my colleague’s “weex entry practice (front-end perspective)”, and for IOS, please refer to my colleague’s “weex practice” (IOS perspective)

2、 Android access process

In fact, for the definition of module and component, as well as the rewriting of iwximgloader adapter, iwxhttppadapter and other adapters, there are already good examples in playcloud and weexteam.

1. Gradle dependence

compile 'com.taobao.android:weex_sdk:0.10.0’

compile 'com.android.support:support-v4:24.0.0'
compile 'com.android.support:appcompat-v7:24.0.0'
compile 'com.android.support:recyclerview-v7:24.0.0'

compile 'com.squareup.okhttp:okhttp:2.3.0'
compile 'com.squareup.okhttp:okhttp-ws:2.3.0'

compile 'com.alibaba:fastjson:1.2.8'

//(optional) for debugging support, refer to https://github.com/weexteam/weex-devtools-android/blob/master/readme-zh.md  
compile 'com.taobao.android:weex_inspector:0.0.8.5'
compile 'com.google.code.findbugs:jsr305:2.0.1'
compile 'com.taobao.android:weex_inspector:0.0.8.5'

2. New weex module

On the original project, create a new separate weex module. The code structure is as follows:

3. Initialize weex

The configuration related to weex is managed uniformly by weexmanager. The following is the main content of init function in weexmanager, which is called in oncreate of application:

public void init(Application application, IWeexService weexService) {

        //Configmanager is the online parameter module of makeup through online parameter control to determine whether to use weex. I will give you a brief introduction in the future
        if (!ConfigManager.getBoolean(CONFIG_WEEX_ENABLE, true)) {
            return;
        }

        context = application.getApplicationContext();
        weexDir = context.getDir(WEEX_MODULE, Context.MODE_PRIVATE);

        //Register image, network, storage and other adapters as required
        WXSDKEngine.initialize(application,
                new InitConfig.Builder()
                        .setImgAdapter(new FrescoImageAdapter())
                        .setUtAdapter(new UserTrackAdapter())
                        .setStorageAdapter(new StorageAdapter())
                        .setHttpAdapter(new OkHttpAdapter())
                        .setURIAdapter(new CustomURIAdapter())
                        .build());

        this.weexService = weexService;

        //Get the configuration of weex JS of local cache
        configList = WXJsonUtils.getList(SHStorageManager.get(WEEX_MODULE, WEEX_CONFIG, ""), WeexConfig.class);
        update();

        try {
            //Some common interfaces of page
            WXSDKEngine.registerModule("shopBase", ShopModule.class);
            //Mainly the jump of a tag
            WXSDKEngine.registerModule("event", WXEventModule.class);
            //Modal dialog
            WXSDKEngine.registerModule("shopModal", ModalModule.class);
            //Rewriting picture components with fresco
            WXSDKEngine.registerComponent("image", FrescoImageComponent.class);
        } catch (WXException e) {
            LogUtils.e(e);
        }

        SHEventBus.register(ModuleName.WEEX, "weexDebugHost", new ISHEventBusCallback<String>() {
            @Override
            public void handle(String debugHost, String s) {
                if (!TextUtils.isEmpty(s)) {
                    LogUtils.e(s);
                    return;
                }
                if (TextUtils.isEmpty(debugHost)) {
                    WXEnvironment.sRemoteDebugMode = false;
                } else {
                    WXEnvironment.sRemoteDebugMode = true;
                    WXEnvironment.sRemoteDebugProxyUrl = "ws://" + debugHost + "/debugProxy/native";
                }
                WXSDKEngine.reload();
            }
        });

        SHEventBus.register(ModuleName.WEEX, "netChanged", new ISHEventBusCallback<Boolean>() {
            @Override
            public void handle(Boolean result, String s) {
                if (!TextUtils.isEmpty(s)) {
                    LogUtils.e(s);
                } else {
                    if (result.booleanValue()) {
                        update();
                    }
                }
            }
        });

        //Get the weex configuration and update the JS file
        weexConfigRequest.setCallBack(new IRequestCallBack<SHResponse<List<WeexConfig>>>() {
            @Override
            public void onResponseSuccess(SHResponse<List<WeexConfig>> response) {
                if (response.isSuccess && null != response.data) {
                    SHStorageManager.putToDisk(WEEX_MODULE, WEEX_CONFIG, JsonUtils.toJson(response.data));
                    configList = response.data;
                    update();
                }
            }

            @Override
            public void onResponseError(int i) {

            }
        });
        weexConfigRequest.start();

    }

1) Considering the first access to weex, I’m a little worried about compatibility. In case of any uncertain factors such as crash, a switch is made here. In fact, it’s better to have aControl switchTo avoid instability due to uncertainties.

2) Weexdir is the download storage path of JS. In order to speed up the page opening time, JS will bePreload to local

3) The SDK only calls the OpenURL interface of “event” for a tag processing, but it does not register"event"。 So we need to implement wxeventmodule and register.

4) Modal dialogModalModuleRefer to wxmod AluI module in SDK for implementation of

5)FrescoImageAdapterandFrescoImageComponentOur open-source shmageview supports webp, compression and link without protocol (ignoring the protocol can let the browser automatically choose the protocol to use according to HTTP or HTTPS when the page is displayed, so as to avoid the problem that the website still accesses HTTP resources and cannot be accessed when it is changed to HTTPS.)

6) The implementation of okhttpadapter refers to the implementation of zjutkz on GitHub. Thanks for rewriting. It supports links without protocol and cookies

7) ShopModule is a customized Module, which defines some general interfaces, such as setting whether the title bar is displayed, and the title bar title; closing the current page, sharing, error log collection, etc.

8) Usertrackadapter is used for burying points. In addition, you can customize the interface in shopmodule to collect burying points, error information, etc.

9) The customuriadapter is used to support relative addresses. See the following for details:

public class CustomURIAdapter implements URIAdapter {
    @NonNull
    @Override
    public Uri rewrite(WXSDKInstance instance, String type, Uri uri) {
        if (null == uri) {
            return null;
        }
        String url = uri.toString();
        if (url.startsWith("http")) {
            return uri;
        }else if (url.startsWith("//")) {
            if (SHStorageManager.get("APP", "https", true)) {
                url = "https:" + url;
            }else {
                url = "http:" + url;
            }
        }else {
            url = SHHost.getMobileHost() + url;
        }
        return Uri.parse(url);
    }
}

4. New unified weex page

Considering that the page may be embedded into other activities in the future, we put the rendering of weex into the new oneWeexFragment。 Then create a new weexactivity to reference the weexfragment. This is used for weex rendering of all individual pagesWeexActivity, use of non separate pagesweexFragment, so that when you add a new page, you do not need to re register the activity. Weex processing logic is unified, convenient for management and dynamic configuration.Jump to weexactivity through unified jump protocol, and pass in two parameters URL and H5 through intent

showjoyshop://page.sh/weex

Intent parameter:
url: JS link, which can be the local storage address / sdcard / com.showjoy.shop/weex/order.js, or the online link https://xxxxx/0.4.3/order.js

h5: the H5 page link used for degradation, when rendering fails, will jump to the H5 page

5. Start rendering JS, and degrade to H5 after failure

Instantiate wxsdkinstance first

wxInstance = new WXSDKInstance(activity);
wxInstance.registerRenderListener(this);
wxInstance.onActivityCreate();
registerBroadcastReceiver();

1) The current class implements the interface iwxrenderlistener, which can refer to the implementation of absweexactivity in weexteam

2) The registered broadcast is defaultbroadcastreceiver. You can refer to the implementation of absweexactivity in weexteam

Then let’s talk about rendering, which supports local JS and online JS

if (url.startsWith("http")) {
    wxInstance.renderByUrl(
            getPageName(),
            url,
            options,
            jsonInitData,
            CommonUtils.getDisplayWidth(activity),
            CommonUtils.getDisplayHeight(activity),
            WXRenderStrategy.APPEND_ASYNC);

}else {
    new Thread(new Runnable() {
        @Override
        public void run() {
            String file = WeexUtils.readFile(url);
            handler.sendMessage(handler.obtainMessage(LOAD_LOCAL_FILE, file));
        }
    }).start();
}

Among them, getpagename() can be customized, and getdisplaywidth and getdisplayheight can get the screen width and height.

When passing in the local storage address, first read the file, and then render the same handler in the UI thread, as follows:

The implementation in the handler after receiving load? Local? File:

case LOAD_LOCAL_FILE:
                    if (activity.getLifeState() != LifeState.DESTORY ) {
                        if (wxInstance != null) {
                            String content = (String) msg.obj;
                            if (TextUtils.isEmpty(content)) {
                                SHJump.openUrl(activity, h5Url);
                                finishActivity();
                            }else {
                                wxInstance.render((String) msg.obj, null, null);
                            }
                        }
                    }
                    break;

Here getlifestate() is our own implementation of baseactivity, which can be judged by ourselves. Shjump and finishactivity are both their own implementations. You can implement them yourself.

The implementation of the rendering callback can be processed as needed. After the rendering is successful, the loading is hidden, and after the view is created, the view is added.Degradation jump to H5 when rendering exception。 As follows:

Override
public void onViewCreated(WXSDKInstance instance, View view) {
    //viewMap.put(weexJsUrl, view);
    addWeexView(view);
}
@Override
public void onRenderSuccess(WXSDKInstance instance, int width, int height) {
    toHideLoading();
}
@Override
public void onRefreshSuccess(WXSDKInstance instance, int width, int height) {
    toHideLoading();
}
@Override
public void onException(WXSDKInstance instance, String errCode, String msg) {
    LogUtils.e("weex exception:", errCode, msg);
    SHJump.openUrlForce(activity, h5Url);
    finishActivity();
}

6. Multiple JS render on the same page

In order to implement the tab as shown in the figure, the tabbar component was used in the. Vue file at first, but later it was found that it was not good enough in Android model adaptation. So later, we will make two tabs into two pages and generate two JS files. First, render “my order. JS” to generate the following interface.

Then, when clicking “our order”, call the interface in the custom moduleloadPage, link with parameter H5.The three terminal interface loadpage, H5 jump directly, and IOS and Android find the corresponding JS from the weex jump configuration through H5 link, and re render the display。 Here are some details:

1) Define map < string, wxsdkinstance > wxsdkinstancemap; to store wxsdkinstance of different JS, define map < string, View > viewmap to store view after different JS rendering. The reason for storing multiple wxsdkinstance is that wxsdkinstance cannot be rendered repeatedly, and after wxsdkinstance destory, the content in the previously rendered view will also be cleared. Note that when the page is destory, just remember to destory all wxsdk instances.

2) The key in the viewmap corresponds to the JS of the page. When clicking the tab to switch the page, if the corresponding JS has been rendered, take out the view directly to display.

3) As mentioned aboveWeex jump configuration, in the following jump rules.

2、 Design of weex support scheme for jump rules of app

The jump rules are shown in the figure below. If you can’t see clearly, you can go to the new page to zoom in.

It mainly introduces two configuration parameters:

  • Configure all weex pages in the parameter weexpages.
    An example is as follows:

[
   {
       "page":"order",
       "url":"https://dshdjshjbx.js",
       "md5":"323827382huwhdjshdjs",
       "h5":"http://dsds.html"
       "v":"1.5.0"
    },
    {
       "page":"detail",
       "url":"https://dsdsds.js",
       "md5":"323827382huwhdjshdjs",
       "h5":"http://dsds.html"
       "v":"1.5.0"
    }
]

page: path corresponding to unified jump

url: JS to be rendered,

md5: the MD5 value of the JS file is used for verification,

h5: degradation scheme after rendering failure,

v: minimum supported version number

When visiting H5 page, compare the URL with the URL in web pages. If it is consistent, open it with web ex. The comparison here is relatively simple and rough at present, and will be optimized later. The ultimate goal isContrast only?In the previous part, the later parameters are passed in to the weex page through intent to participate in the rendering of weex.

In this way, the goal of dynamic interception and dynamic online weex is achieved.

3、 JS preloading scheme

As mentioned earlier, in order to speed up the opening time of weex, JS will be preloaded. Here is the implementation of JS preloading.

  • 1) After each update of the configuration file, traverse to see if there is a MD5 consistent page ﹣ xxx.js file. If not, update it

  • 2) After downloading, save the format as xxx.js and verify MD5

    • If the same, record the last modification time of the file;

    • Otherwise, delete the downloaded file, download again, and repeat the verification process.

  • 3) Support the unified jump protocol. Page corresponds to the page in the current unified jump protocol on the app side. If necessary, the original native page can be replaced to solve the problem that native page errors cannot be fixed in time. If the load fails, open the H5 page.

  • 4) Each time you open a specified page, first check whether there is a corresponding page file locally, and then check whether the last modification time is consistent with the record

    • Load consistently

    • Use online URLs if they are inconsistent.

4、 Problems encountered and Solutions

Problem 1: after going online, it was found that some models failed to render. In the public void onexception (wxsdkinstance, string errCode, string MSG) callback, errCode returned wx_create_instance_error, MSG returned createinstance fail!

Terms of settlement: after decompressing APK, it is found that five packages supporting ABI are compiled. However, libweexv8.so is only available in armeabi and x86, and lacks support for the other three ABIS. If the application is running on a device with arm64-v8a, x86 ʄ, armeabi-v7a as the preferred ABI, it will fail to load. In fact, the three Abis arm64-v8a, armeabi-v7a, and x86 ʄ 64 are not necessarily supported by the application, and the mobile phone generally provides automatic compatibility. So we just need to remove the support for x86, arm64-v8a, x86 ʄ. Add the following content to the defaultconfig in the Android of build.gradle of the main module as follows:

defaultConfig {  
    ndk {  
        abiFilters "armeabi", "x86"  
    }  
}

Problem 2: an parsing exception occurred when onhttpfinish was called in okhttpadapter, the log is as follows:

com.alibaba.fastjson.JSONException: syntax error, pos 2
    at com.alibaba.fastjson.parser.DefaultJSONParser.parse(DefaultJSONParser.java:1300)
    at com.alibaba.fastjson.parser.DefaultJSONParser.parse(DefaultJSONParser.java:1210)
    at com.alibaba.fastjson.JSON.parse(JSON.java:109)
    at com.alibaba.fastjson.JSON.parse(JSON.java:100)
    at com.taobao.weex.http.WXStreamModule.parseJson(WXStreamModule.java:378)
    at com.taobao.weex.http.WXStreamModule$2.onResponse(WXStreamModule.java:365)
    at com.taobao.weex.http.WXStreamModule$StreamHttpListener.onHttpFinish(WXStreamModule.java:523)
    at com.showjoy.weex.commons.adapter.OkHttpAdapter$6.onResponse(OkHttpAdapter.java:161)
    at okhttp3.RealCall$AsyncCall.execute(RealCall.java:133)
    at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
    at java.lang.Thread.run(Thread.java:818) 

Resolvent: catch exception

try {
    if (null != listener) {
        listener.onHttpFinish(wxResponse);
    }
} catch (Exception e) {
    LogUtils.e(e);
}

Problem 3: relative address and online and offline environment switching.

Resolvent: relative address is supported in the latest version. Relative address is used for link and request address in. Vue file. The domain name used in H5 page is automatically selected, while it is blocked in IOS and Android, and corresponding domain name is added according to the current environment.

  • Android implements uriadapter injection

  • IOS implementation of wxurlnewriteprotocol injection

Reference link:
https://github.com/weexteam/
http://weex-project.io/doc/
https://github.com/alibaba/weex/

Recommended Today

RCAST 35: add type to currency

– font ALT: Simsun; MSO font charset: 134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 680460288 22 0 262145 0;} @font-face {font-family:”Cambria Math”; panose-1:2 4 5 3 5 4 6 3 2 4; mso-font-charset:1; mso-generic-font-family:roman; mso-font-format:other; mso-font-pitch:variable; mso-font-signature:0 0 0 0 0 0;} @font-face {font-family:Calibri; Variable; Ose-1: 216301111; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 680460288 22 0 262145 0;} /\* Style […]