| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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 org.apache.weex.bridge; |
| |
| import android.content.Intent; |
| import android.support.annotation.NonNull; |
| import android.text.TextUtils; |
| import android.view.Menu; |
| |
| import com.alibaba.fastjson.JSONArray; |
| import org.apache.weex.WXSDKInstance; |
| import org.apache.weex.WXSDKManager; |
| import org.apache.weex.WXSDKEngine; |
| import org.apache.weex.adapter.IWXUserTrackAdapter; |
| import org.apache.weex.common.Destroyable; |
| import org.apache.weex.common.WXException; |
| import org.apache.weex.common.WXModule; |
| import org.apache.weex.ui.config.ConfigModuleFactory; |
| import org.apache.weex.ui.module.WXDomModule; |
| import org.apache.weex.ui.module.WXTimerModule; |
| import org.apache.weex.utils.WXLogUtils; |
| import org.apache.weex.utils.cache.RegisterCache; |
| |
| import java.io.Serializable; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| import java.util.concurrent.ConcurrentHashMap; |
| import java.util.concurrent.ConcurrentMap; |
| import org.apache.weex.utils.cache.RegisterCache.ModuleCache; |
| |
| /** |
| * Manager class for weex module. There are two types of modules in weex, one is instance-level module, |
| * the other is global-level module. Instance-level module will be created every time an instance |
| * is created, while global-level module will be singleton in {@link WXSDKEngine}. |
| */ |
| public class WXModuleManager { |
| |
| /** |
| * module class object dictionary |
| */ |
| private static volatile ConcurrentMap<String, ModuleFactoryImpl> sModuleFactoryMap = new ConcurrentHashMap<>(); |
| private static Map<String, WXModule> sGlobalModuleMap = new HashMap<>(); |
| private static Map<String, WXDomModule> sDomModuleMap = new HashMap<>(); |
| |
| |
| /** |
| * module object dictionary |
| * K : instanceId, V : Modules |
| */ |
| private static Map<String, Map<String, WXModule>> sInstanceModuleMap = new ConcurrentHashMap<>(); |
| |
| |
| public static boolean registerModule(Map<String, ModuleCache> moduleCacheMap) { |
| if (moduleCacheMap.isEmpty()) |
| return true; |
| |
| final Iterator<Entry<String, ModuleCache>> iterator = moduleCacheMap.entrySet().iterator(); |
| WXBridgeManager.getInstance() |
| .postWithName(new Runnable() { |
| @Override |
| public void run() { |
| Map<String, Object> modules = new HashMap<>(); |
| |
| while (iterator.hasNext()) { |
| Entry<String, ModuleCache> next = iterator.next(); |
| ModuleCache value = next.getValue(); |
| String moduleName = value.name; |
| if (TextUtils.equals(moduleName, WXDomModule.WXDOM)) { |
| WXLogUtils.e("Cannot registered module with name 'dom'."); |
| continue; |
| } |
| |
| if (sModuleFactoryMap != null && sModuleFactoryMap.containsKey(moduleName)) { |
| WXLogUtils.w("WXComponentRegistry Duplicate the Module name: " + moduleName); |
| } |
| ModuleFactory factory = value.factory; |
| try { |
| registerNativeModule(moduleName, factory); |
| } catch (WXException e) { |
| WXLogUtils.e("registerNativeModule" + e); |
| } |
| |
| if (value.global) { |
| try { |
| WXModule wxModule = factory.buildInstance(); |
| wxModule.setModuleName(moduleName); |
| sGlobalModuleMap.put(moduleName, wxModule); |
| } catch (Exception e) { |
| WXLogUtils.e(moduleName + " class must have a default constructor without params. ", e); |
| } |
| } |
| |
| try { |
| sModuleFactoryMap.put(moduleName, new ModuleFactoryImpl(factory)); |
| } catch (Throwable e) { |
| |
| } |
| modules.put(moduleName, factory.getMethods()); |
| } |
| WXSDKManager.getInstance().registerModules(modules); |
| } |
| },null,"registerModule From Cache"); |
| return true; |
| } |
| |
| /** |
| * Register module to JavaScript and Android |
| */ |
| public static boolean registerModule(final String moduleName, final ModuleFactory factory, final boolean global) throws WXException { |
| if (moduleName == null || factory == null) { |
| return false; |
| } |
| |
| if (TextUtils.equals(moduleName,WXDomModule.WXDOM)) { |
| WXLogUtils.e("Cannot registered module with name 'dom'."); |
| return false; |
| } |
| |
| if(RegisterCache.getInstance().cacheModule(moduleName,factory,global)) { |
| return true; |
| } |
| |
| //execute task in js thread to make sure register order is same as the order invoke register method. |
| WXBridgeManager.getInstance() |
| .postWithName(new Runnable() { |
| @Override |
| public void run() { |
| if (sModuleFactoryMap != null && sModuleFactoryMap.containsKey(moduleName)) { |
| WXLogUtils.w("WXComponentRegistry Duplicate the Module name: " + moduleName); |
| } |
| try { |
| registerNativeModule(moduleName, factory); |
| } catch (WXException e) { |
| WXLogUtils.e("registerNativeModule" + e); |
| } |
| |
| if (global) { |
| try { |
| WXModule wxModule = factory.buildInstance(); |
| wxModule.setModuleName(moduleName); |
| sGlobalModuleMap.put(moduleName, wxModule); |
| } catch (Exception e) { |
| WXLogUtils.e(moduleName + " class must have a default constructor without params. ", e); |
| } |
| } |
| |
| registerJSModule(moduleName, factory); |
| |
| try { |
| sModuleFactoryMap.put(moduleName, new ModuleFactoryImpl(factory)); |
| } catch (Throwable e) { |
| |
| } |
| } |
| },null,"registerModule"); |
| return true; |
| |
| } |
| |
| static boolean registerNativeModule(String moduleName, ModuleFactory factory) throws WXException { |
| if (factory == null) { |
| return false; |
| } |
| |
| try { |
| if (!sModuleFactoryMap.containsKey(moduleName) ) { |
| sModuleFactoryMap.put(moduleName, new ModuleFactoryImpl(factory)); |
| } |
| }catch (ArrayStoreException e){ |
| e.printStackTrace(); |
| //ignore: |
| //may throw this exception: |
| //java.lang.String cannot be stored in an array of type java.util.HashMap$HashMapEntry[] |
| |
| WXLogUtils.e("[WXModuleManager] registerNativeModule Error moduleName:" + moduleName + " Error:" + e.toString()); |
| } |
| return true; |
| } |
| |
| static boolean registerJSModule(String moduleName, ModuleFactory factory) { |
| Map<String, Object> modules = new HashMap<>(); |
| modules.put(moduleName, factory.getMethods()); |
| WXSDKManager.getInstance().registerModules(modules); |
| return true; |
| } |
| |
| static Object callModuleMethod(final String instanceId, String moduleStr, String methodStr, JSONArray args) { |
| ModuleFactory factory = sModuleFactoryMap.get(moduleStr).mFactory; |
| if(factory == null){ |
| WXLogUtils.e("[WXModuleManager] module factory not found."); |
| return null; |
| } |
| final WXModule wxModule = findModule(instanceId, moduleStr,factory); |
| if (wxModule == null) { |
| return null; |
| } |
| WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId); |
| wxModule.mWXSDKInstance = instance; |
| |
| final Invoker invoker = factory.getMethodInvoker(methodStr); |
| try { |
| if(instance != null) { |
| IWXUserTrackAdapter userTrackAdapter = WXSDKManager.getInstance().getIWXUserTrackAdapter(); |
| if(userTrackAdapter != null) { |
| HashMap<String, Serializable> data = new HashMap<String, Serializable>(); |
| data.put(IWXUserTrackAdapter.MONITOR_ERROR_CODE, "101"); |
| data.put(IWXUserTrackAdapter.MONITOR_ARG, moduleStr + "." + methodStr); |
| data.put(IWXUserTrackAdapter.MONITOR_ERROR_MSG, instance.getBundleUrl()); |
| userTrackAdapter.commit(instance.getContext(), null, IWXUserTrackAdapter.INVOKE_MODULE, null, data); |
| } |
| return dispatchCallModuleMethod(instance,wxModule,args,invoker); |
| } else { |
| WXLogUtils.e("callModuleMethod >>> instance is null"); |
| return null; |
| } |
| } catch (Exception e) { |
| WXLogUtils.e("callModuleMethod >>> invoke module:" + moduleStr + ", method:" + methodStr + " failed. ", e); |
| return null; |
| } finally { |
| if (wxModule instanceof WXDomModule || wxModule instanceof WXTimerModule) { |
| wxModule.mWXSDKInstance = null; |
| } |
| } |
| } |
| |
| private static Object dispatchCallModuleMethod(@NonNull WXSDKInstance instance, @NonNull WXModule wxModule, |
| @NonNull JSONArray args, @NonNull Invoker invoker) throws Exception{ |
| if(!instance.isPreRenderMode()) { |
| return instance.getNativeInvokeHelper().invoke(wxModule,invoker,args); |
| } |
| // we are in preRender mode |
| if(invoker.isRunOnUIThread()) {/*ASYNC CALL*/ |
| // DOMAction moduleInvocationAction = Actions.getModuleInvocationAction(wxModule,args,invoker); |
| // WXSDKManager.getInstance().getWXDomManager().postAction(instance.getInstanceId(), moduleInvocationAction,false); |
| return null; |
| } else {/*SYNC CALL*/ |
| return instance.getNativeInvokeHelper().invoke(wxModule,invoker,args); |
| } |
| } |
| |
| public static boolean hasModule(String module) { |
| return sGlobalModuleMap.containsKey(module) || sModuleFactoryMap.containsKey(module); |
| } |
| |
| private static WXModule findModule(String instanceId, String moduleStr,ModuleFactory factory) { |
| // find WXModule |
| WXModule wxModule = sGlobalModuleMap.get(moduleStr); |
| |
| //not global module |
| if (wxModule == null) { |
| Map<String, WXModule> moduleMap = sInstanceModuleMap.get(instanceId); |
| if (moduleMap == null) { |
| moduleMap = new ConcurrentHashMap<>(); |
| sInstanceModuleMap.put(instanceId, moduleMap); |
| } |
| // if cannot find the Module, create a new Module and save it |
| wxModule = moduleMap.get(moduleStr); |
| if (wxModule == null) { |
| try { |
| if(factory instanceof ConfigModuleFactory){ |
| WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId); |
| wxModule = ((ConfigModuleFactory) factory).buildInstance(instance); |
| }else{ |
| wxModule = factory.buildInstance(); |
| } |
| wxModule.setModuleName(moduleStr); |
| } catch (Exception e) { |
| WXLogUtils.e(moduleStr + " module build instace failed.", e); |
| return null; |
| } |
| moduleMap.put(moduleStr, wxModule); |
| } |
| } |
| |
| return wxModule; |
| } |
| |
| /**Hook Activity life cycle callback begin***/ |
| |
| |
| public static void onActivityCreate(String instanceId){ |
| |
| Map<String, WXModule> modules = sInstanceModuleMap.get(instanceId); |
| if(modules!=null) { |
| for (String key : modules.keySet()) { |
| WXModule module = modules.get(key); |
| if (module != null) { |
| module.onActivityCreate(); |
| } else { |
| WXLogUtils.w("onActivityCreate can not find the " + key + " module"); |
| } |
| } |
| } |
| |
| } |
| |
| public static void onActivityStart(String instanceId){ |
| |
| Map<String, WXModule> modules = sInstanceModuleMap.get(instanceId); |
| if(modules!=null) { |
| for (String key : modules.keySet()) { |
| WXModule module = modules.get(key); |
| if (module != null) { |
| module.onActivityStart(); |
| } else { |
| WXLogUtils.w("onActivityStart can not find the " + key + " module"); |
| } |
| } |
| } |
| } |
| |
| public static void onActivityPause(String instanceId){ |
| Map<String, WXModule> modules = sInstanceModuleMap.get(instanceId); |
| if(modules!=null) { |
| for (String key : modules.keySet()) { |
| WXModule module = modules.get(key); |
| if (module != null) { |
| module.onActivityPause(); |
| } else { |
| WXLogUtils.w("onActivityPause can not find the " + key + " module"); |
| } |
| } |
| } |
| } |
| |
| public static void onActivityResume(String instanceId){ |
| Map<String, WXModule> modules = sInstanceModuleMap.get(instanceId); |
| if(modules!=null) { |
| for (String key : modules.keySet()) { |
| WXModule module = modules.get(key); |
| if (module != null) { |
| module.onActivityResume(); |
| } else { |
| WXLogUtils.w("onActivityResume can not find the " + key + " module"); |
| } |
| } |
| } |
| } |
| |
| public static void onActivityStop(String instanceId){ |
| Map<String, WXModule> modules = sInstanceModuleMap.get(instanceId); |
| if(modules!=null) { |
| for (String key : modules.keySet()) { |
| WXModule module = modules.get(key); |
| if (module != null) { |
| module.onActivityStop(); |
| } else { |
| WXLogUtils.w("onActivityStop can not find the " + key + " module"); |
| } |
| } |
| } |
| } |
| |
| public static void onActivityDestroy(String instanceId){ |
| Map<String, WXModule> modules = sInstanceModuleMap.get(instanceId); |
| if(modules!=null) { |
| for (String key : modules.keySet()) { |
| WXModule module = modules.get(key); |
| if (module != null) { |
| module.onActivityDestroy(); |
| } else { |
| WXLogUtils.w("onActivityDestroy can not find the " + key + " module"); |
| } |
| } |
| } |
| } |
| |
| public static boolean onActivityBack(String instanceId){ |
| Map<String, WXModule> modules = sInstanceModuleMap.get(instanceId); |
| if(modules!=null) { |
| for (String key : modules.keySet()) { |
| WXModule module = modules.get(key); |
| if (module != null) { |
| return module.onActivityBack(); |
| } else { |
| WXLogUtils.w("onActivityCreate can not find the " + key + " module"); |
| } |
| } |
| } |
| return false; |
| } |
| |
| public static void onActivityResult(String instanceId,int requestCode, int resultCode, Intent data){ |
| |
| Map<String, WXModule> modules = sInstanceModuleMap.get(instanceId); |
| if(modules!=null) { |
| for (String key : modules.keySet()) { |
| WXModule module = modules.get(key); |
| if (module != null) { |
| module.onActivityResult(requestCode, resultCode, data); |
| } else { |
| WXLogUtils.w("onActivityResult can not find the " + key + " module"); |
| } |
| } |
| } |
| } |
| |
| public static boolean onCreateOptionsMenu(String instanceId,Menu menu) { |
| Map<String, WXModule> modules = sInstanceModuleMap.get(instanceId); |
| if(modules!=null) { |
| for (String key : modules.keySet()) { |
| WXModule module = modules.get(key); |
| if (module != null) { |
| module.onCreateOptionsMenu(menu); |
| } else { |
| WXLogUtils.w("onActivityResult can not find the " + key + " module"); |
| } |
| } |
| } |
| return false; |
| } |
| |
| public static void onRequestPermissionsResult(String instanceId ,int requestCode, String[] permissions, int[] grantResults) { |
| Map<String, WXModule> modules = sInstanceModuleMap.get(instanceId); |
| if(modules!=null) { |
| for (String key : modules.keySet()) { |
| WXModule module = modules.get(key); |
| if (module != null) { |
| module.onRequestPermissionsResult(requestCode, permissions, grantResults); |
| } else { |
| WXLogUtils.w("onActivityResult can not find the " + key + " module"); |
| } |
| } |
| } |
| } |
| |
| public static void destroyInstanceModules(String instanceId) { |
| sDomModuleMap.remove(instanceId); |
| Map<String, WXModule> moduleMap = sInstanceModuleMap.remove(instanceId); |
| if (moduleMap == null || moduleMap.size() < 1) { |
| return; |
| } |
| Iterator<Entry<String, WXModule>> iterator = moduleMap.entrySet().iterator(); |
| Entry<String, WXModule> entry; |
| while (iterator.hasNext()) { |
| entry = iterator.next(); |
| WXModule module = entry.getValue(); |
| if(module instanceof Destroyable){ |
| ((Destroyable)module).destroy(); |
| } |
| |
| } |
| } |
| |
| public static void createDomModule(WXSDKInstance instance){ |
| if(instance != null) { |
| sDomModuleMap.put(instance.getInstanceId(), new WXDomModule(instance)); |
| } |
| } |
| |
| public static void destoryDomModule(String instanceID){ |
| sDomModuleMap.remove(instanceID); |
| } |
| |
| public static WXDomModule getDomModule(String instanceId){ |
| return sDomModuleMap.get(instanceId); |
| } |
| |
| public static void reload(){ |
| if (sModuleFactoryMap != null && sModuleFactoryMap.size() > 0) { |
| for (Map.Entry<String, ModuleFactoryImpl> entry : sModuleFactoryMap.entrySet()) { |
| try { |
| registerJSModule(entry.getKey(), entry.getValue().mFactory); |
| } catch (Throwable e) { |
| |
| } |
| } |
| } |
| } |
| |
| /** |
| * registerWhenCreateInstance |
| */ |
| public static void registerWhenCreateInstance(){ |
| if (sModuleFactoryMap != null && sModuleFactoryMap.size() > 0) { |
| for (Map.Entry<String, ModuleFactoryImpl> entry : sModuleFactoryMap.entrySet()) { |
| try { |
| if (!entry.getValue().hasRigster) { |
| registerJSModule(entry.getKey(), entry.getValue().mFactory); |
| } |
| } catch (Throwable e) { |
| |
| } |
| } |
| } |
| } |
| |
| /** |
| * resetAllModuleState |
| */ |
| public static void resetAllModuleState() { |
| if (sModuleFactoryMap != null && sModuleFactoryMap.size() > 0) { |
| for (Map.Entry<String, ModuleFactoryImpl> entry : sModuleFactoryMap.entrySet()) { |
| entry.getValue().hasRigster = false; |
| } |
| } |
| } |
| |
| /** |
| * resetModuleState |
| * @param module |
| * @param state |
| */ |
| public static void resetModuleState(String module, boolean state) { |
| if (sModuleFactoryMap != null && sModuleFactoryMap.size() > 0) { |
| for (Map.Entry<String, ModuleFactoryImpl> entry : sModuleFactoryMap.entrySet()) { |
| try { |
| if (entry.getKey() != null && entry.getKey().equals(module)) { |
| entry.getValue().hasRigster = state; |
| } |
| } catch (Throwable e) { |
| |
| } |
| } |
| } |
| } |
| } |