/**
*
* 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);
}
}