/** * * Apache License * Version 2.0, January 2004 * http://www.apache.org/licenses/ * * TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION * * 1. Definitions. * * "License" shall mean the terms and conditions for use, reproduction, * and distribution as defined by Sections 1 through 9 of this document. * * "Licensor" shall mean the copyright owner or entity authorized by * the copyright owner that is granting the License. * * "Legal Entity" shall mean the union of the acting entity and all * other entities that control, are controlled by, or are under common * control with that entity. For the purposes of this definition, * "control" means (i) the power, direct or indirect, to cause the * direction or management of such entity, whether by contract or * otherwise, or (ii) ownership of fifty percent (50%) or more of the * outstanding shares, or (iii) beneficial ownership of such entity. * * "You" (or "Your") shall mean an individual or Legal Entity * exercising permissions granted by this License. * * "Source" form shall mean the preferred form for making modifications, * including but not limited to software source code, documentation * source, and configuration files. * * "Object" form shall mean any form resulting from mechanical * transformation or translation of a Source form, including but * not limited to compiled object code, generated documentation, * and conversions to other media types. * * "Work" shall mean the work of authorship, whether in Source or * Object form, made available under the License, as indicated by a * copyright notice that is included in or attached to the work * (an example is provided in the Appendix below). * * "Derivative Works" shall mean any work, whether in Source or Object * form, that is based on (or derived from) the Work and for which the * editorial revisions, annotations, elaborations, or other modifications * represent, as a whole, an original work of authorship. For the purposes * of this License, Derivative Works shall not include works that remain * separable from, or merely link (or bind by name) to the interfaces of, * the Work and Derivative Works thereof. * * "Contribution" shall mean any work of authorship, including * the original version of the Work and any modifications or additions * to that Work or Derivative Works thereof, that is intentionally * submitted to Licensor for inclusion in the Work by the copyright owner * or by an individual or Legal Entity authorized to submit on behalf of * the copyright owner. For the purposes of this definition, "submitted" * means any form of electronic, verbal, or written communication sent * to the Licensor or its representatives, including but not limited to * communication on electronic mailing lists, source code control systems, * and issue tracking systems that are managed by, or on behalf of, the * Licensor for the purpose of discussing and improving the Work, but * excluding communication that is conspicuously marked or otherwise * designated in writing by the copyright owner as "Not a Contribution." * * "Contributor" shall mean Licensor and any individual or Legal Entity * on behalf of whom a Contribution has been received by Licensor and * subsequently incorporated within the Work. * * 2. Grant of Copyright License. Subject to the terms and conditions of * this License, each Contributor hereby grants to You a perpetual, * worldwide, non-exclusive, no-charge, royalty-free, irrevocable * copyright license to reproduce, prepare Derivative Works of, * publicly display, publicly perform, sublicense, and distribute the * Work and such Derivative Works in Source or Object form. * * 3. Grant of Patent License. Subject to the terms and conditions of * this License, each Contributor hereby grants to You a perpetual, * worldwide, non-exclusive, no-charge, royalty-free, irrevocable * (except as stated in this section) patent license to make, have made, * use, offer to sell, sell, import, and otherwise transfer the Work, * where such license applies only to those patent claims licensable * by such Contributor that are necessarily infringed by their * Contribution(s) alone or by combination of their Contribution(s) * with the Work to which such Contribution(s) was submitted. If You * institute patent litigation against any entity (including a * cross-claim or counterclaim in a lawsuit) alleging that the Work * or a Contribution incorporated within the Work constitutes direct * or contributory patent infringement, then any patent licenses * granted to You under this License for that Work shall terminate * as of the date such litigation is filed. * * 4. Redistribution. You may reproduce and distribute copies of the * Work or Derivative Works thereof in any medium, with or without * modifications, and in Source or Object form, provided that You * meet the following conditions: * * (a) You must give any other recipients of the Work or * Derivative Works a copy of this License; and * * (b) You must cause any modified files to carry prominent notices * stating that You changed the files; and * * (c) You must retain, in the Source form of any Derivative Works * that You distribute, all copyright, patent, trademark, and * attribution notices from the Source form of the Work, * excluding those notices that do not pertain to any part of * the Derivative Works; and * * (d) If the Work includes a "NOTICE" text file as part of its * distribution, then any Derivative Works that You distribute must * include a readable copy of the attribution notices contained * within such NOTICE file, excluding those notices that do not * pertain to any part of the Derivative Works, in at least one * of the following places: within a NOTICE text file distributed * as part of the Derivative Works; within the Source form or * documentation, if provided along with the Derivative Works; or, * within a display generated by the Derivative Works, if and * wherever such third-party notices normally appear. The contents * of the NOTICE file are for informational purposes only and * do not modify the License. You may add Your own attribution * notices within Derivative Works that You distribute, alongside * or as an addendum to the NOTICE text from the Work, provided * that such additional attribution notices cannot be construed * as modifying the License. * * You may add Your own copyright statement to Your modifications and * may provide additional or different license terms and conditions * for use, reproduction, or distribution of Your modifications, or * for any such Derivative Works as a whole, provided Your use, * reproduction, and distribution of the Work otherwise complies with * the conditions stated in this License. * * 5. Submission of Contributions. Unless You explicitly state otherwise, * any Contribution intentionally submitted for inclusion in the Work * by You to the Licensor shall be under the terms and conditions of * this License, without any additional terms or conditions. * Notwithstanding the above, nothing herein shall supersede or modify * the terms of any separate license agreement you may have executed * with Licensor regarding such Contributions. * * 6. Trademarks. This License does not grant permission to use the trade * names, trademarks, service marks, or product names of the Licensor, * except as required for reasonable and customary use in describing the * origin of the Work and reproducing the content of the NOTICE file. * * 7. Disclaimer of Warranty. Unless required by applicable law or * agreed to in writing, Licensor provides the Work (and each * Contributor provides its Contributions) on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied, including, without limitation, any warranties or conditions * of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A * PARTICULAR PURPOSE. You are solely responsible for determining the * appropriateness of using or redistributing the Work and assume any * risks associated with Your exercise of permissions under this License. * * 8. Limitation of Liability. In no event and under no legal theory, * whether in tort (including negligence), contract, or otherwise, * unless required by applicable law (such as deliberate and grossly * negligent acts) or agreed to in writing, shall any Contributor be * liable to You for damages, including any direct, indirect, special, * incidental, or consequential damages of any character arising as a * result of this License or out of the use or inability to use the * Work (including but not limited to damages for loss of goodwill, * work stoppage, computer failure or malfunction, or any and all * other commercial damages or losses), even if such Contributor * has been advised of the possibility of such damages. * * 9. Accepting Warranty or Additional Liability. While redistributing * the Work or Derivative Works thereof, You may choose to offer, * and charge a fee for, acceptance of support, warranty, indemnity, * or other liability obligations and/or rights consistent with this * License. However, in accepting such obligations, You may act only * on Your own behalf and on Your sole responsibility, not on behalf * of any other Contributor, and only if You agree to indemnify, * defend, and hold each Contributor harmless for any liability * incurred by, or claims asserted against, such Contributor by reason * of your accepting any such warranty or additional liability. * * END OF TERMS AND CONDITIONS * * APPENDIX: How to apply the Apache License to your work. * * To apply the Apache License to your work, attach the following * boilerplate notice, with the fields enclosed by brackets "[]" * replaced with your own identifying information. (Don't include * the brackets!) The text should be enclosed in the appropriate * comment syntax for the file format. We also recommend that a * file or class name and description of purpose be included on the * same "printed page" as the copyright notice for easier * identification within third-party archives. * * Copyright 2016 Alibaba Group * * 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. */ package com.taobao.weex; import android.content.Context; import android.net.Uri; import android.os.Message; import android.text.TextUtils; import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.widget.ScrollView; import com.alibaba.fastjson.JSONObject; import com.taobao.weex.adapter.IWXHttpAdapter; import com.taobao.weex.adapter.IWXImgLoaderAdapter; import com.taobao.weex.adapter.IWXUserTrackAdapter; import com.taobao.weex.bridge.WXBridgeManager; import com.taobao.weex.common.Constants; import com.taobao.weex.common.OnWXScrollListener; import com.taobao.weex.common.WXErrorCode; import com.taobao.weex.common.WXPerformance; import com.taobao.weex.common.WXRefreshData; import com.taobao.weex.common.WXRenderStrategy; import com.taobao.weex.common.WXRequest; import com.taobao.weex.common.WXResponse; import com.taobao.weex.dom.WXDomHandler; import com.taobao.weex.dom.WXDomObject; import com.taobao.weex.dom.WXDomTask; import com.taobao.weex.http.WXHttpUtil; import com.taobao.weex.ui.component.NestedContainer; import com.taobao.weex.ui.component.WXComponent; import com.taobao.weex.ui.component.WXVContainer; import com.taobao.weex.ui.view.WXScrollView; import com.taobao.weex.ui.view.WXScrollView.WXScrollViewListener; import com.taobao.weex.utils.WXFileUtils; import com.taobao.weex.utils.WXJsonUtils; import com.taobao.weex.utils.WXLogUtils; import com.taobao.weex.utils.WXReflectionUtils; import com.taobao.weex.utils.WXViewUtils; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentLinkedQueue; /** * Each instance of WXSDKInstance represents an running weex instance. * It can be a pure weex view, or mixed with native view */ public class WXSDKInstance implements IWXActivityStateListener { //Performance public boolean mEnd = false; public static final String BUNDLE_URL = "bundleUrl"; protected IWXUserTrackAdapter mUserTrackAdapter; protected IWXHttpAdapter mWXHttpAdapter; private IWXRenderListener mRenderListener; Context mContext; volatile String mInstanceId; private WXComponent mGodCom; private boolean mRendered; private WXRefreshData mLastRefreshData; private float refreshMargin = 0; private NestedInstanceInterceptor mNestedInstanceInterceptor; private String mBundleUrl = ""; private boolean isDestroy=false; /** * Render strategy. */ private WXRenderStrategy mRenderStrategy = WXRenderStrategy.APPEND_ASYNC; /** * Width of weex's root container. */ private int mGodViewWidth = -1; /** * Height of weex's root container. */ private int mGodViewHeight = -1; /** * Render start time */ private long mRenderStartTime; /** * Refresh start time */ private long mRefreshStartTime; private ConcurrentLinkedQueue<IWXActivityStateListener> mActivityStateListeners = new ConcurrentLinkedQueue<>(); private WXPerformance mWXPerformance; private ScrollView mScrollView; private WXScrollViewListener mWXScrollViewListener; private List<OnWXScrollListener> mWXScrollListeners; private ViewGroup rootView; public interface OnInstanceVisibleListener{ void onAppear(); void onDisappear(); } private List<OnInstanceVisibleListener> mVisibleListeners = new ArrayList<>(); public WXSDKInstance(Context context) { init(context); } public WXComponent getGodCom() { return mGodCom; } public WXComponent getRootCom() { if (getGodCom() == null) return null; else return ((WXVContainer) (this.getGodCom())).getChild(0); } public void setNestedInstanceInterceptor(NestedInstanceInterceptor interceptor){ mNestedInstanceInterceptor = interceptor; } public WXSDKInstance createNestedInstance(NestedContainer container){ WXSDKInstance sdkInstance = new WXSDKInstance(mContext); if(mNestedInstanceInterceptor != null){ mNestedInstanceInterceptor.onCreateNestInstance(sdkInstance,container); } return sdkInstance; } public void addOnInstanceVisibleListener(OnInstanceVisibleListener l){ mVisibleListeners.add(l); } public void removeOnInstanceVisibleListener(OnInstanceVisibleListener l){ mVisibleListeners.remove(l); } public void init(Context context) { mContext = context; mWXPerformance = new WXPerformance(); mWXPerformance.WXSDKVersion = WXEnvironment.WXSDK_VERSION; mWXPerformance.JSLibInitTime = WXEnvironment.sJSLibInitTime; mUserTrackAdapter=WXSDKManager.getInstance().getIWXUserTrackAdapter(); mWXHttpAdapter=WXSDKManager.getInstance().getIWXHttpAdapter(); } public void setBizType(String bizType) { if (!TextUtils.isEmpty(bizType)) { mWXPerformance.bizType = bizType; } } public ScrollView getScrollView() { return mScrollView; } public void setRootScrollView(ScrollView scrollView) { mScrollView = scrollView; if (mWXScrollViewListener != null) { ((WXScrollView) mScrollView).addScrollViewListener(mWXScrollViewListener); } } @Deprecated public void registerScrollViewListener(WXScrollViewListener scrollViewListener) { mWXScrollViewListener = scrollViewListener; } @Deprecated public WXScrollViewListener getScrollViewListener() { return mWXScrollViewListener; } @Deprecated public void setIWXUserTrackAdapter(IWXUserTrackAdapter adapter) { } /** * Render template asynchronously, use {@link WXRenderStrategy#APPEND_ASYNC} as render strategy * @param template bundle js * @param options os iphone/android/ipad * weexversion Weex version(like 1.0.0) * appversion App version(like 1.0.0) * devid Device id(like Aqh9z8dRJNBhmS9drLG5BKCmXhecHUXIZoXOctKwFebH) * sysversion Device system version(like 5.4.4、7.0.4, should be used with os) * sysmodel Device model(like iOS:"MGA82J/A", android:"MI NOTE LTE") * Time UNIX timestamp, UTC+08:00 * TTID(Optional) * MarkertId * Appname(Optional) tm,tb,qa * Bundleurl(Optional) template url * @param jsonInitData Initial data for rendering */ public void render(String template, Map<String, Object> options, String jsonInitData) { render(template, options, jsonInitData, WXRenderStrategy.APPEND_ASYNC); } /** * Render template asynchronously * @param template bundle js * @param options os iphone/android/ipad * weexversion Weex version(like 1.0.0) * appversion App version(like 1.0.0) * devid Device id(like Aqh9z8dRJNBhmS9drLG5BKCmXhecHUXIZoXOctKwFebH) * sysversion Device system version(like 5.4.4、7.0.4, should be used with os) * sysmodel Device model(like iOS:"MGA82J/A", android:"MI NOTE LTE") * Time UNIX timestamp, UTC+08:00 * TTID(Optional) * MarkertId * Appname(Optional) tm,tb,qa * Bundleurl(Optional) template url * @param jsonInitData Initial data for rendering * @param flag RenderStrategy {@link WXRenderStrategy} */ public void render(String template, Map<String, Object> options, String jsonInitData, WXRenderStrategy flag) { render(WXPerformance.DEFAULT, template, options, jsonInitData, -1, -1, flag); } /** * Render template asynchronously * * @param pageName, used for performance log. * @param template bundle js * @param options os iphone/android/ipad * weexversion Weex version(like 1.0.0) * appversion App version(like 1.0.0) * devid Device id(like Aqh9z8dRJNBhmS9drLG5BKCmXhecHUXIZoXOctKwFebH) * sysversion Device system version(like 5.4.4、7.0.4, should be used with os) * sysmodel Device model(like iOS:"MGA82J/A", android:"MI NOTE LTE") * Time UNIX timestamp, UTC+08:00 * TTID(Optional) * MarkertId * Appname(Optional) tm,tb,qa * Bundleurl(Optional) template url * @param jsonInitData Initial data for rendering * @param width Width of weex's root container, the default is match_parent * @param height Height of weex's root container, the default is match_parent * @param flag RenderStrategy {@link WXRenderStrategy} */ public void render(String pageName, String template, Map<String, Object> options, String jsonInitData, int width, int height, WXRenderStrategy flag) { if (mRendered || TextUtils.isEmpty(template)) { return; } if(options==null){ options=new HashMap<>(); } if(WXEnvironment.sDynamicMode && !TextUtils.isEmpty(WXEnvironment.sDynamicUrl) && options!=null && options.get("dynamicMode")==null){ options.put("dynamicMode","true"); renderByUrl(pageName, WXEnvironment.sDynamicUrl, options, jsonInitData, width, height, flag); return; } mWXPerformance.pageName = pageName; mWXPerformance.JSTemplateSize = template.length() / 1024; mRenderStartTime = System.currentTimeMillis(); mRenderStrategy = flag; mGodViewWidth = width; mGodViewHeight = height; mInstanceId = WXSDKManager.getInstance().generateInstanceId(); WXSDKManager.getInstance().createInstance(this, template, options, jsonInitData); mRendered = true; if(TextUtils.isEmpty(mBundleUrl)){ mBundleUrl=pageName; } } /** * Render template asynchronously, use {@link WXRenderStrategy#APPEND_ASYNC} as render strategy * @param template bundle js * @param width default match_parent * @param height default match_parent */ public void render(String template, int width, int height) { render(WXPerformance.DEFAULT, template, null, null, width, height, mRenderStrategy); } public void renderByUrl(String pageName, final String url, Map<String, Object> options, final String jsonInitData, final int width, final int height, final WXRenderStrategy flag) { pageName = wrapPageName(pageName, url); mBundleUrl = url; if (options == null) { options = new HashMap<String, Object>(); } if (!options.containsKey(BUNDLE_URL)) { options.put(BUNDLE_URL, url); } Uri uri=Uri.parse(url); if(uri!=null && TextUtils.equals(uri.getScheme(),"file")){ render(pageName, WXFileUtils.loadAsset(assembleFilePath(uri), mContext),options,jsonInitData,width,height,flag); return; } IWXHttpAdapter adapter=WXSDKManager.getInstance().getIWXHttpAdapter(); WXRequest wxRequest = new WXRequest(); wxRequest.url = url; if (wxRequest.paramMap == null) { wxRequest.paramMap = new HashMap<String, String>(); } wxRequest.paramMap.put("user-agent", WXHttpUtil.assembleUserAgent(mContext,WXEnvironment.getConfig())); adapter.sendRequest(wxRequest, new WXHttpListener(pageName, options, jsonInitData, width, height, flag, System.currentTimeMillis())); mWXHttpAdapter = adapter; } private String wrapPageName(String pageName, String url) { if(TextUtils.equals(pageName, WXPerformance.DEFAULT)){ pageName=url; try { Uri uri=Uri.parse(url); if(uri!=null){ Uri.Builder builder=new Uri.Builder(); builder.scheme(uri.getScheme()); builder.authority(uri.getAuthority()); builder.path(uri.getPath()); pageName=builder.toString(); } } catch (Exception e) { } } return pageName; } private String assembleFilePath(Uri uri) { if(uri!=null && uri.getPath()!=null){ return uri.getPath().replaceFirst("/",""); } return ""; } /** * Refresh instance asynchronously. * @param data the new data */ public void refreshInstance(Map<String, Object> data) { if (data == null) { return; } refreshInstance(WXJsonUtils.fromObjectToJSONString(data)); } /** * Refresh instance asynchronously. * @param jsonData the new data */ public void refreshInstance(String jsonData) { if (jsonData == null) { return; } mRefreshStartTime = System.currentTimeMillis(); //cancel last refresh message if (mLastRefreshData != null) { mLastRefreshData.isDirty = true; } mLastRefreshData = new WXRefreshData(jsonData, false); WXSDKManager.getInstance().refreshInstance(mInstanceId, mLastRefreshData); } public WXRenderStrategy getRenderStrategy() { return mRenderStrategy; } public String getInstanceId() { return mInstanceId; } public Context getContext() { if(mContext == null){ WXLogUtils.e("WXSdkInstance mContext == null"); } return mContext; } public int getWeexHeight() { return mGodViewHeight; } public int getWeexWidth() { return mGodViewWidth; } public IWXImgLoaderAdapter getImgLoaderAdapter() { return WXSDKManager.getInstance().getIWXImgLoaderAdapter(); } @Deprecated public void setImgLoaderAdapter(IWXImgLoaderAdapter adapter) { } public IWXHttpAdapter getWXHttpAdapter() { return WXSDKManager.getInstance().getIWXHttpAdapter(); } public void reloadImages() { if (mScrollView == null) { return; } } /******************************** * begin register listener ********************************************************/ public void registerRenderListener(IWXRenderListener listener) { mRenderListener = listener; } public void registerActivityStateListener(IWXActivityStateListener listener) { if (listener == null || mActivityStateListeners==null) { return; } if(mActivityStateListeners == null){ mActivityStateListeners = new ConcurrentLinkedQueue<>(); } if (!mActivityStateListeners.contains(listener)) { mActivityStateListeners.add(listener); } } /******************************** * end register listener ********************************************************/ // WAActivityStateListener////////////////////////////////////////////////////////////////////////////////// @Override public void onActivityCreate() { for (IWXActivityStateListener listener : mActivityStateListeners) { listener.onActivityCreate(); } } @Override public void onActivityStart() { for (IWXActivityStateListener listener : mActivityStateListeners) { listener.onActivityStart(); } } @Override public void onActivityPause() { for (IWXActivityStateListener listener : mActivityStateListeners) { listener.onActivityPause(); } onViewDisappear(); } public void onViewDisappear(){ WXComponent comp = getRootCom(); if(comp != null) { WXBridgeManager.getInstance().fireEvent(this.mInstanceId, comp.getRef(), Constants.Event.VIEWDISAPPEAR, null, null); //call disappear of nested instances for(OnInstanceVisibleListener instance:mVisibleListeners){ instance.onDisappear(); } } } public void onViewAppear(){ WXComponent comp = getRootCom(); if(comp != null) { WXBridgeManager.getInstance().fireEvent(this.mInstanceId, comp.getRef(), Constants.Event.VIEWAPPEAR,null, null); for(OnInstanceVisibleListener instance:mVisibleListeners){ instance.onAppear(); } } } @Override public void onActivityResume() { for (IWXActivityStateListener listener : mActivityStateListeners) { listener.onActivityResume(); } onViewAppear(); } @Override public void onActivityStop() { for (IWXActivityStateListener listener : mActivityStateListeners) { listener.onActivityStop(); } } @Override public void onActivityDestroy() { for (IWXActivityStateListener listener : mActivityStateListeners) { listener.onActivityDestroy(); } destroy(); } @Override public boolean onActivityBack() { for (IWXActivityStateListener listener : mActivityStateListeners) { boolean isIntercept = listener.onActivityBack(); if (isIntercept) { return true; } } return false; } public void onViewCreated(final WXComponent component) { if (mRenderListener != null && mContext != null) { runOnUiThread(new Runnable() { @Override public void run() { if (mRenderListener != null && mContext != null) { mGodCom = component; onViewAppear(); View wxView=component.getHostView(); if(WXEnvironment.isApkDebugable() && WXSDKManager.getInstance().getIWXDebugAdapter()!=null){ wxView=WXSDKManager.getInstance().getIWXDebugAdapter().wrapContainer(WXSDKInstance.this,wxView); } mRenderListener.onViewCreated(WXSDKInstance.this, wxView); } } }); } } /** * call back when update finish */ public void onUpdateFinish() { WXLogUtils.d("Instance onUpdateSuccess"); } public void runOnUiThread(Runnable action) { WXSDKManager.getInstance().postOnUiThread(action, 0); } public void onRenderSuccess(final int width, final int height) { long time = System.currentTimeMillis() - mRenderStartTime; WXLogUtils.renderPerformanceLog("onRenderSuccess", time); WXLogUtils.renderPerformanceLog(" invokeCreateInstance",mWXPerformance.communicateTime); WXLogUtils.renderPerformanceLog(" TotalCallNativeTime", mWXPerformance.callNativeTime); WXLogUtils.renderPerformanceLog(" TotalJsonParseTime", mWXPerformance.parseJsonTime); WXLogUtils.renderPerformanceLog(" TotalBatchTime", mWXPerformance.batchTime); WXLogUtils.renderPerformanceLog(" TotalCssLayoutTime", mWXPerformance.cssLayoutTime); WXLogUtils.renderPerformanceLog(" TotalApplyUpdateTime", mWXPerformance.applyUpdateTime); WXLogUtils.renderPerformanceLog(" TotalUpdateDomObjTime", mWXPerformance.updateDomObjTime); mWXPerformance.totalTime = time; if(mWXPerformance.screenRenderTime<0.001){ mWXPerformance.screenRenderTime = time; } mWXPerformance.componentCount = WXComponent.mComponentNum; if(WXEnvironment.isApkDebugable()) { WXLogUtils.d(WXLogUtils.WEEX_PERF_TAG, "mComponentNum:" + WXComponent.mComponentNum); } WXComponent.mComponentNum = 0; if (mRenderListener != null && mContext != null) { runOnUiThread(new Runnable() { @Override public void run() { if (mRenderListener != null && mContext != null) { mRenderListener.onRenderSuccess(WXSDKInstance.this, width, height); if (WXEnvironment.isApkDebugable()) { WXLogUtils.d(WXLogUtils.WEEX_PERF_TAG, mWXPerformance.toString()); } if (mUserTrackAdapter != null) { mUserTrackAdapter.commit(mContext, null, IWXUserTrackAdapter.LOAD, mWXPerformance, null); commitUTStab(IWXUserTrackAdapter.JS_BRIDGE,WXErrorCode.WX_SUCCESS); } } } }); } if(!WXEnvironment.isApkDebugable()){ Log.e("weex_perf",mWXPerformance.getPerfData()); } } public void onRefreshSuccess(final int width, final int height) { WXLogUtils.renderPerformanceLog("onRefreshSuccess", (System.currentTimeMillis() - mRefreshStartTime)); if (mRenderListener != null && mContext != null) { runOnUiThread(new Runnable() { @Override public void run() { if (mRenderListener != null && mContext != null) { mRenderListener.onRefreshSuccess(WXSDKInstance.this, width, height); } } }); } } public void onRenderError(final String errCode, final String msg) { if (mRenderListener != null && mContext != null) { runOnUiThread(new Runnable() { @Override public void run() { if (mRenderListener != null && mContext != null) { mRenderListener.onException(WXSDKInstance.this, errCode, msg); } } }); } } public void onJSException(final String errCode, final String function, final String exception) { if (mRenderListener != null && mContext != null) { runOnUiThread(new Runnable() { @Override public void run() { if (mRenderListener != null && mContext != null) { StringBuilder builder = new StringBuilder(); builder.append(function); builder.append(exception); mRenderListener.onException(WXSDKInstance.this, errCode, builder.toString()); } } }); } } private boolean mCreateInstance =true; public void firstScreenCreateInstanceTime(long time) { if(mCreateInstance) { mWXPerformance.firstScreenJSFExecuteTime = time -mRenderStartTime; mCreateInstance =false; } } public void callNativeTime(long time) { mWXPerformance.callNativeTime += time; } public void jsonParseTime(long time) { mWXPerformance.parseJsonTime += time; } public void firstScreenRenderFinished() { mEnd = true; mWXPerformance.screenRenderTime = System.currentTimeMillis() - mRenderStartTime; WXLogUtils.renderPerformanceLog("firstScreenRenderFinished", mWXPerformance.screenRenderTime); WXLogUtils.renderPerformanceLog(" firstScreenJSFExecuteTime", mWXPerformance.firstScreenJSFExecuteTime); WXLogUtils.renderPerformanceLog(" firstScreenCallNativeTime", mWXPerformance.callNativeTime); WXLogUtils.renderPerformanceLog(" firstScreenJsonParseTime", mWXPerformance.parseJsonTime); WXLogUtils.renderPerformanceLog(" firstScreenBatchTime", mWXPerformance.batchTime); WXLogUtils.renderPerformanceLog(" firstScreenCssLayoutTime", mWXPerformance.cssLayoutTime); WXLogUtils.renderPerformanceLog(" firstScreenApplyUpdateTime", mWXPerformance.applyUpdateTime); WXLogUtils.renderPerformanceLog(" firstScreenUpdateDomObjTime", mWXPerformance.updateDomObjTime); } public void batchTime(long time) { mWXPerformance.batchTime += time; } public void cssLayoutTime(long time) { mWXPerformance.cssLayoutTime += time; } public void applyUpdateTime(long time) { mWXPerformance.applyUpdateTime += time; } public void updateDomObjTime(long time) { mWXPerformance.updateDomObjTime += time; } public void createInstanceFinished(long time) { if (time > 0) { mWXPerformance.communicateTime = time; } } /** * UserTrack Log */ public void commitUTStab(final String type, final WXErrorCode errorCode) { if (mUserTrackAdapter == null || TextUtils.isEmpty(type) || errorCode==null) { return; } runOnUiThread(new Runnable() { @Override public void run() { WXPerformance performance = null; if (errorCode != WXErrorCode.WX_SUCCESS) { performance = new WXPerformance(); performance.errCode = errorCode.getErrorCode(); performance.errMsg = errorCode.getErrorMsg(); if (WXEnvironment.isApkDebugable()) { WXLogUtils.d(performance.toString()); } } if( mUserTrackAdapter!= null) { mUserTrackAdapter.commit(mContext, null, type, performance, null); } } }); } private void destroyView(View rootView) { try { if (rootView instanceof ViewGroup) { ViewGroup cViewGroup = ((ViewGroup) rootView); for (int index = 0; index < cViewGroup.getChildCount(); index++) { destroyView(cViewGroup.getChildAt(index)); } cViewGroup.removeViews(0, ((ViewGroup) rootView).getChildCount()); // Ensure that the viewgroup's status to be normal WXReflectionUtils.setValue(rootView, "mChildrenCount", 0); } } catch (Exception e) { WXLogUtils.e("WXSDKInstance destroyView Exception: ", e); } } public synchronized void destroy() { WXSDKManager.getInstance().destroyInstance(mInstanceId); if (mGodCom != null && mGodCom.getHostView() != null) { mGodCom.destroy(); destroyView(mGodCom.getHostView()); mGodCom = null; } if (mActivityStateListeners != null) { mActivityStateListeners.clear(); mActivityStateListeners = null; } if(mGlobalEvents!=null){ mGlobalEvents.clear(); } mNestedInstanceInterceptor = null; mUserTrackAdapter = null; mWXHttpAdapter = null; rootView = null; mScrollView = null; mContext = null; mRenderListener = null; isDestroy=true; } public boolean isDestroy(){ return isDestroy; } public String getBundleUrl() { return mBundleUrl; } public ViewGroup getRootView() { return rootView; } public void setRootView(ViewGroup rootView) { this.rootView = rootView; } public synchronized List<OnWXScrollListener> getWXScrollListeners() { return mWXScrollListeners; } public synchronized void registerOnWXScrollListener(OnWXScrollListener wxScrollListener) { if(mWXScrollListeners==null){ mWXScrollListeners=new ArrayList<>(); } mWXScrollListeners.add(wxScrollListener); } public float getRefreshMargin() { return refreshMargin; } public void setRefreshMargin(float refreshMargin) { this.refreshMargin = refreshMargin; } private void updateRootComponentStyle(JSONObject style) { Message message = Message.obtain(); WXDomTask task = new WXDomTask(); task.instanceId = getInstanceId(); if (task.args == null) { task.args = new ArrayList<>(); } task.args.add(WXDomObject.ROOT); task.args.add(style); message.obj = task; message.what = WXDomHandler.MsgType.WX_DOM_UPDATE_STYLE; WXSDKManager.getInstance().getWXDomManager().sendMessage(message); } public void setSize(int width, int height) { if (width < 0 || height < 0) { return; } mGodViewWidth = width; mGodViewHeight = height; float realWidth = WXViewUtils.getWebPxByWidth(width); float realHeight = WXViewUtils.getWebPxByWidth(height); View godView = mGodCom.getHostView(); if (godView != null) { ViewGroup.LayoutParams layoutParams = godView.getLayoutParams(); if (layoutParams != null) { layoutParams.width = width; layoutParams.height = height; godView.setLayoutParams(layoutParams); JSONObject style = new JSONObject(); if (mGodCom instanceof WXVContainer) { WXComponent rootComponent = ((WXVContainer) mGodCom).getChild(0); if (rootComponent != null && rootComponent.getDomObject() != null && rootComponent.getDomObject().isModifyHeight()) { style.put(Constants.Name.HEIGHT, realHeight); } if (rootComponent != null && rootComponent.getDomObject() != null && rootComponent.getDomObject().isModifyWidth()) { style.put(Constants.Name.WIDTH, realWidth); } updateRootComponentStyle(style); } } } } /*Global Event*/ private HashMap<String, List<String>> mGlobalEvents = new HashMap<>(); public void fireGlobalEventCallback(String eventName, Map<String,Object> params){ List<String> callbacks=mGlobalEvents.get(eventName); if(callbacks!=null){ for(String callback:callbacks){ WXSDKManager.getInstance().callback(mInstanceId,callback,params,true); } } } /** * Fire event callback on a element. * @param elementRef * @param type * @param data * @param domChanges */ public void fireEvent(String elementRef,final String type, final Map<String, Object> data,final Map<String, Object> domChanges){ WXBridgeManager.getInstance().fireEventOnNode(getInstanceId(),elementRef,type,data,domChanges); } public void fireEvent(String elementRef,final String type, final Map<String, Object> data){ fireEvent(elementRef,type,data,null); } public void fireEvent(String ref, String type){ fireEvent(ref,type,new HashMap<String, Object>()); } protected void addEventListener(String eventName, String callback) { if (TextUtils.isEmpty(eventName) || TextUtils.isEmpty(callback)) { return; } List<String> callbacks = mGlobalEvents.get(eventName); if (callbacks == null) { callbacks = new ArrayList<>(); mGlobalEvents.put(eventName, callbacks); } callbacks.add(callback); } protected void removeEventListener(String eventName, String callback) { if (TextUtils.isEmpty(eventName) || TextUtils.isEmpty(callback)) { return; } List<String> callbacks = mGlobalEvents.get(eventName); if (callbacks != null) { callbacks.remove(callback); } } protected void removeEventListener(String eventName) { if (TextUtils.isEmpty(eventName)) { return; } mGlobalEvents.remove(eventName); } /** * load bundle js listener */ class WXHttpListener implements IWXHttpAdapter.OnHttpListener { private String pageName; private Map<String, Object> options; private String jsonInitData; private int width; private int height; private WXRenderStrategy flag; private long startRequestTime; private WXHttpListener(String pageName, Map<String, Object> options, String jsonInitData, int width, int height, WXRenderStrategy flag, long startRequestTime) { this.pageName = pageName; this.options = options; this.jsonInitData = jsonInitData; this.width = width; this.height = height; this.flag = flag; this.startRequestTime = startRequestTime; } @Override public void onHttpStart() { } @Override public void onHeadersReceived(int statusCode,Map<String,List<String>> headers) { } @Override public void onHttpUploadProgress(int uploadProgress) { } @Override public void onHttpResponseProgress(int loadedLength) { } @Override public void onHttpFinish(WXResponse response) { mWXPerformance.networkTime = System.currentTimeMillis() - startRequestTime; if(response.extendParams!=null){ Object actualNetworkTime=response.extendParams.get("actualNetworkTime"); mWXPerformance.actualNetworkTime=actualNetworkTime instanceof Long?(long)actualNetworkTime:0; WXLogUtils.renderPerformanceLog("actualNetworkTime", mWXPerformance.actualNetworkTime); Object pureNetworkTime=response.extendParams.get("pureNetworkTime"); mWXPerformance.pureNetworkTime=pureNetworkTime instanceof Long?(long)pureNetworkTime:0; WXLogUtils.renderPerformanceLog("pureNetworkTime", mWXPerformance.pureNetworkTime); Object connectionType=response.extendParams.get("connectionType"); mWXPerformance.connectionType=connectionType instanceof String?(String)connectionType:""; Object packageSpendTime=response.extendParams.get("packageSpendTime"); mWXPerformance.packageSpendTime=packageSpendTime instanceof Long ?(long)packageSpendTime:0; Object syncTaskTime=response.extendParams.get("syncTaskTime"); mWXPerformance.syncTaskTime=syncTaskTime instanceof Long ?(long)syncTaskTime:0; Object requestType=response.extendParams.get("requestType"); mWXPerformance.requestType=requestType instanceof String?(String)requestType:""; } WXLogUtils.renderPerformanceLog("networkTime", mWXPerformance.networkTime); if (response!=null && response.originalData!=null && TextUtils.equals("200", response.statusCode)) { String template = new String(response.originalData); render(pageName, template, options, jsonInitData, width, height, flag); } else if (TextUtils.equals(WXRenderErrorCode.WX_USER_INTERCEPT_ERROR, response.statusCode)) { WXLogUtils.d("user intercept"); onRenderError(WXRenderErrorCode.WX_USER_INTERCEPT_ERROR,response.errorMsg); } else { onRenderError(WXRenderErrorCode.WX_NETWORK_ERROR, response.errorMsg); } } } public interface NestedInstanceInterceptor { void onCreateNestInstance(WXSDKInstance instance, NestedContainer container); } }