| /* |
| * 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. |
| */ |
| |
| #import "WXSDKError.h" |
| #import "WXCoreBridge.h" |
| #import "JSValue+Weex.h" |
| #import "WXSDKManager.h" |
| #import "WXComponentManager.h" |
| #import "WXSDKInstance_private.h" |
| #import "WXLog.h" |
| #import "WXBridgeProtocol.h" |
| #import "WXUtility.h" |
| #import "WXAssert.h" |
| #import "WXAppConfiguration.h" |
| #import "WXConvertUtility.h" |
| #import "WXSDKEngine.h" |
| #import "WXAppMonitorProtocol.h" |
| #import "WXComponentMethod.h" |
| #import "WXExceptionUtils.h" |
| #import "WXModuleFactory.h" |
| #import "WXComponentFactory.h" |
| #import "WXRichText.h" |
| #include "base/core_constants.h" |
| #include "base/time_utils.h" |
| #include "base/log_defines.h" |
| #include "core/manager/weex_core_manager.h" |
| #include "core/render/manager/render_manager.h" |
| #include "core/render/target/render_target.h" |
| #include "core/render/page/render_page.h" |
| #include "core/render/page/render_page_custom.h" |
| #include "core/render/node/render_object.h" |
| #include "core/render/node/render_list.h" |
| #include "core/render/node/factory/render_type.h" |
| #include "core/render/node/factory/render_creator.h" |
| #include "core/config/core_environment.h" |
| #include "core/bridge/platform/core_side_in_platform.h" |
| #include "core/bridge/script/core_side_in_script.h" |
| #include "core/network/http_module.h" |
| |
| #import <objc/runtime.h> |
| #include <fstream> |
| |
| namespace WeexCore |
| { |
| static void consoleWithArguments(NSArray *arguments, WXLogFlag logLevel) |
| { |
| NSMutableString *jsLog = [NSMutableString string]; |
| [jsLog appendString:@"jsLog: "]; |
| [arguments enumerateObjectsUsingBlock:^(NSString *jsVal, NSUInteger idx, BOOL *stop) { |
| if (idx == arguments.count - 1) { |
| if (logLevel) { |
| if (WXLogFlagWarning == logLevel || WXLogFlagError == logLevel) { |
| id<WXAppMonitorProtocol> appMonitorHandler = [WXSDKEngine handlerForProtocol:@protocol(WXAppMonitorProtocol)]; |
| if ([appMonitorHandler respondsToSelector:@selector(commitAppMonitorAlarm:monitorPoint:success:errorCode:errorMsg:arg:)]) { |
| [appMonitorHandler commitAppMonitorAlarm:@"weex" monitorPoint:@"jswarning" success:NO errorCode:@"99999" errorMsg:jsLog arg:[WXSDKEngine topInstance].pageName]; |
| } |
| } |
| WX_LOG(logLevel, @"%@", jsLog); |
| } |
| else { |
| [jsLog appendFormat:@"%@ ", jsVal]; |
| WXLogInfo(@"%@", jsLog); |
| } |
| } |
| else { |
| [jsLog appendFormat:@"%@ ", jsVal]; |
| } |
| }]; |
| } |
| |
| static void MergeBorderWidthValues(NSMutableDictionary* dict, |
| const WXCoreBorderWidth & borders, |
| bool isUpdate, float pixelScaleFactor) |
| { |
| if (pixelScaleFactor <= 0) { |
| pixelScaleFactor = 1.0f; |
| } |
| if (borders.getBorderWidth(kBorderWidthTop) != (float)0.0f || isUpdate) { |
| dict[@"borderTopWidth"] = @(borders.getBorderWidth(kBorderWidthTop) / pixelScaleFactor); |
| } |
| if (borders.getBorderWidth(kBorderWidthLeft) != (float)0.0f || isUpdate) { |
| dict[@"borderLeftWidth"] = @(borders.getBorderWidth(kBorderWidthLeft) / pixelScaleFactor); |
| } |
| if (borders.getBorderWidth(kBorderWidthBottom) != (float)0.0f || isUpdate) { |
| dict[@"borderBottomWidth"] = @(borders.getBorderWidth(kBorderWidthBottom) / pixelScaleFactor); |
| } |
| if (borders.getBorderWidth(kBorderWidthRight) != (float)0.0f || isUpdate) { |
| dict[@"borderRightWidth"] = @(borders.getBorderWidth(kBorderWidthRight) / pixelScaleFactor); |
| } |
| } |
| |
| static void MergeBorderWidthValues(NSMutableDictionary* dict, |
| std::vector<std::pair<std::string, std::string>>* borders, |
| float pixelScaleFactor) |
| { |
| if (borders == nullptr) { |
| return; |
| } |
| if (pixelScaleFactor <= 0) { |
| pixelScaleFactor = 1.0f; |
| } |
| |
| for (auto& p : *borders) { |
| dict[NSSTRING(p.first.c_str())] = @(atof(p.second.c_str()) / pixelScaleFactor); |
| } |
| } |
| |
| void IOSSide::SetJSVersion(const char* version) |
| { |
| NSString *jsVersion = NSSTRING(version); |
| if (jsVersion.length > 0) { |
| [WXAppConfiguration setJSFrameworkVersion:jsVersion]; |
| } |
| } |
| |
| void IOSSide::ReportException(const char *page_id, const char *func, const char *exception) |
| { |
| do { |
| WXSDKInstance *instance = [WXSDKManager instanceForID:NSSTRING(page_id)]; |
| if (!instance) { |
| break; |
| } |
| WXSDKErrCode errorCode = WX_ERR_JS_EXECUTE; |
| BOOL is_render_failed = NO; |
| if (func && (strcmp(func, "CreatePageWithContent") == 0 || strcmp(func, "UpdateComponentData") == 0)) { |
| errorCode = WX_KEY_EXCEPTION_DEGRADE_EAGLE_RENDER_ERROR; |
| WXComponentManager *manager = instance.componentManager; |
| if (manager.isValid) { |
| NSError *error = [NSError errorWithDomain:WX_ERROR_DOMAIN code:errorCode userInfo:@{@"message":[NSString stringWithUTF8String:exception], @"exception function:":@(func)}]; |
| [manager renderFailed:error]; |
| } |
| is_render_failed = YES; |
| } |
| NSString *bundleUrl = instance.pageName ? : ([instance.scriptURL absoluteString] ? : @"WX_KEY_EXCEPTION_WXBRIDGE"); |
| NSMutableDictionary *userInfo = [[NSMutableDictionary alloc] init]; |
| [userInfo setObject:instance.userInfo[@"jsMainBundleStringContentLength"] ? : @"" forKey:@"jsMainBundleStringContentLength"]; |
| [userInfo setObject:instance.userInfo[@"jsMainBundleStringContentMd5"] ? : @"" forKey:@"jsMainBundleStringContentMd5"]; |
| WXJSExceptionInfo *jsException = [[WXJSExceptionInfo alloc] initWithInstanceId:instance.instanceId bundleUrl:bundleUrl errorCode: [NSString stringWithFormat:@"%d", errorCode] functionName:func ? [NSString stringWithUTF8String:func] :@"exceptionHandler" exception:exception ? [NSString stringWithUTF8String:exception] : @"unkown" userInfo:userInfo]; |
| [WXExceptionUtils commitCriticalExceptionRT:jsException.instanceId errCode:jsException.errorCode function:jsException.functionName exception:jsException.exception extParams:jsException.userInfo]; |
| if (!is_render_failed && instance.onJSRuntimeException) { |
| instance.onJSRuntimeException(jsException); |
| } |
| |
| } while (0); |
| |
| } |
| |
| int IOSSide::CallNative(const char* pageId, const char *task, const char *callback) |
| { |
| // should not enter this function |
| assert(false); //!OCLint |
| } |
| |
| static WeexByteArray *generator_bytes_array(const char *str, size_t len) { |
| auto *result = (WeexByteArray *)malloc(len + sizeof(WeexByteArray)); |
| do { |
| if (!result) { |
| break; |
| } |
| memset(result, 0, len + sizeof(WeexByteArray)); |
| result->length = static_cast<uint32_t>(len); |
| memcpy(result->content, str, len); |
| result->content[len] = '\0'; |
| |
| } while (0); |
| |
| return result; |
| } |
| std::unique_ptr<ValueWithType> IOSSide::RegisterPluginComponent(const char *pcstr_name, const char *pcstr_class_name, const char *pcstr_version) { |
| ValueWithType *returnValue = new ValueWithType(); |
| memset(returnValue, 0, sizeof(ValueWithType)); |
| returnValue->type = ParamsType::VOID; |
| do { |
| if (!pcstr_class_name) { |
| break; |
| } |
| NSString *className = [NSString stringWithUTF8String:pcstr_class_name]; |
| Class clazz = NSClassFromString(className); |
| if (!clazz) { |
| break; |
| } |
| if (!pcstr_name) { |
| break; |
| } |
| NSDictionary *properties = @{ @"append" : @"tree" }; |
| NSString *name = [NSString stringWithUTF8String:pcstr_name]; |
| [WXComponentFactory registerComponent:name withClass:clazz withPros:properties]; |
| NSMutableDictionary *info = [WXComponentFactory componentMethodMapsWithName:name]; |
| if (![info isKindOfClass:[NSDictionary class]]) { |
| break; |
| } |
| NSArray *methods = info[@"methods"]; |
| if (![methods isKindOfClass:[NSArray class]] || !methods.count) { |
| break; |
| } |
| info[@"type"] = name; |
| NSMutableDictionary *props = [properties mutableCopy]; |
| [props addEntriesFromDictionary:info]; |
| NSString *componentsInfo = [WXUtility JSONString:@[props]]; |
| if (componentsInfo.length > 0) { |
| returnValue->type = ParamsType::BYTEARRAYSTRING; |
| const char *pcstr_utf8 = [componentsInfo UTF8String]; |
| returnValue->value.byteArray = generator_bytes_array(pcstr_utf8, componentsInfo.length); |
| } |
| |
| } while (0); |
| |
| return std::unique_ptr<ValueWithType>(returnValue); |
| } |
| |
| std::unique_ptr<ValueWithType> IOSSide::RegisterPluginModule(const char *pcstr_name, const char *pcstr_class_name, const char *pcstr_version) { |
| ValueWithType *returnValue = new ValueWithType(); |
| memset(returnValue, 0, sizeof(ValueWithType)); |
| returnValue->type = ParamsType::VOID; |
| do { |
| if (!pcstr_class_name) { |
| break; |
| } |
| NSString *className = [NSString stringWithUTF8String:pcstr_class_name]; |
| Class clazz = NSClassFromString(className); |
| if (!clazz) { |
| break; |
| } |
| if (!pcstr_name) { |
| break; |
| } |
| NSString *name = [NSString stringWithUTF8String:pcstr_name]; |
| NSString *moduleName = [WXModuleFactory registerModule:name withClass:clazz]; |
| if (!moduleName.length) { |
| break; |
| } |
| NSDictionary *moduleInfo = [WXModuleFactory moduleMethodMapsWithName:moduleName]; |
| if (!moduleInfo || ![moduleInfo isKindOfClass:[NSDictionary class]]) { |
| break; |
| } |
| NSString *setting = [WXUtility JSONString:moduleInfo]; |
| if (setting.length > 0) { |
| returnValue->type = ParamsType::BYTEARRAYSTRING; |
| const char *pcstr_utf8 = [setting UTF8String]; |
| returnValue->value.byteArray = generator_bytes_array(pcstr_utf8, setting.length); |
| } |
| |
| } while (0); |
| |
| return std::unique_ptr<ValueWithType>(returnValue); |
| } |
| std::unique_ptr<ValueWithType> IOSSide::CallNativeModule(const char *page_id, const char *module, const char *method, const char *args, int args_length, const char *options, int options_length) |
| { |
| ValueWithType *returnValue = new ValueWithType(); |
| memset(returnValue, 0, sizeof(ValueWithType)); |
| returnValue->type = ParamsType::VOID; |
| // should not enter this function |
| do { |
| NSString *instanceId = NSSTRING(page_id); |
| WXSDKInstance *instance = [WXSDKManager instanceForID:instanceId]; |
| if (!instance) { |
| break; |
| } |
| NSString *moduleName = [NSString stringWithUTF8String:module]; |
| NSString *methodName = [NSString stringWithUTF8String:method]; |
| NSArray *newArguments; |
| if (args && args_length > 0) { |
| NSString *arguments = [NSString stringWithUTF8String:args]; |
| newArguments = [WXUtility objectFromJSON:arguments]; |
| } |
| LOGD("CallNativeModule:[%s]:[%s]=>%s \n", module, method, args); |
| WXModuleMethod *method = [[WXModuleMethod alloc] initWithModuleName:moduleName methodName:methodName arguments:newArguments options:nil instance:instance]; |
| NSInvocation *invocation = [method invoke]; |
| if (!invocation) { |
| break; |
| } |
| const char *returnType = [invocation.methodSignature methodReturnType]; |
| switch (returnType[0] == _C_CONST ? returnType[1] : returnType[0]) { |
| case _C_VOID: { |
| // 1.void |
| returnValue->type = ParamsType::VOID; |
| break; |
| } |
| case _C_ID: { |
| // 2.id |
| void *value; |
| [invocation getReturnValue:&value]; |
| id object = (__bridge id)value; |
| if ([object isKindOfClass:[NSString class]]) { |
| returnValue->type = ParamsType::BYTEARRAYSTRING; |
| const char *pcstr_utf8 = [(NSString *)object UTF8String]; |
| returnValue->value.byteArray = generator_bytes_array(pcstr_utf8, ((NSString *)object).length); |
| } |
| if ([object isKindOfClass:[NSDictionary class]] || [object isKindOfClass:[NSArray class]]) { |
| NSString *jsonString = [WXUtility JSONString:object]; |
| returnValue->type = ParamsType::BYTEARRAYJSONSTRING; |
| returnValue->value.byteArray = generator_bytes_array(jsonString.UTF8String, jsonString.length); |
| } |
| break; |
| } |
| #define WX_MODULE_INT32_VALUE_RET_CASE(ctype, ttype) \ |
| case ctype: { \ |
| ttype value; \ |
| [invocation getReturnValue:&value]; \ |
| returnValue->type = ParamsType::INT32; \ |
| returnValue->value.int32Value = value; \ |
| break; \ |
| } |
| #define WX_MODULE_INT64_VALUE_RET_CASE(ctype, ttype) \ |
| case ctype: { \ |
| ttype value; \ |
| [invocation getReturnValue:&value]; \ |
| returnValue->type = ParamsType::INT64; \ |
| returnValue->value.int64Value = value; \ |
| break; \ |
| } |
| // 3.number |
| WX_MODULE_INT32_VALUE_RET_CASE(_C_CHR, char) |
| WX_MODULE_INT32_VALUE_RET_CASE(_C_UCHR, unsigned char) |
| WX_MODULE_INT32_VALUE_RET_CASE(_C_SHT, short) |
| WX_MODULE_INT32_VALUE_RET_CASE(_C_USHT, unsigned short) |
| WX_MODULE_INT32_VALUE_RET_CASE(_C_INT, int) |
| WX_MODULE_INT32_VALUE_RET_CASE(_C_UINT, unsigned int) |
| WX_MODULE_INT32_VALUE_RET_CASE(_C_BOOL, BOOL) |
| WX_MODULE_INT64_VALUE_RET_CASE(_C_LNG, long) |
| WX_MODULE_INT64_VALUE_RET_CASE(_C_ULNG, unsigned long) |
| WX_MODULE_INT64_VALUE_RET_CASE(_C_LNG_LNG, long long) |
| WX_MODULE_INT64_VALUE_RET_CASE(_C_ULNG_LNG, unsigned long long) |
| case _C_FLT: |
| { |
| float value; |
| [invocation getReturnValue:&value]; |
| returnValue->type = ParamsType::FLOAT; |
| returnValue->value.floatValue = value; |
| break; |
| } |
| case _C_DBL: |
| { |
| double value; |
| [invocation getReturnValue:&value]; |
| returnValue->type = ParamsType::DOUBLE; |
| returnValue->value.doubleValue = value; |
| break; |
| } |
| case _C_STRUCT_B: |
| case _C_CHARPTR: |
| case _C_PTR: |
| case _C_CLASS: { |
| returnValue->type = ParamsType::JSUNDEFINED; |
| break; |
| } |
| } |
| |
| } while (0); |
| |
| return std::unique_ptr<ValueWithType>(returnValue); |
| } |
| |
| void IOSSide::CallNativeComponent(const char *page_id, const char *ref, const char *method, |
| const char *args, int args_length, |
| const char *options, int options_length) |
| { |
| do { |
| NSString *instanceId = NSSTRING(page_id); |
| WXSDKInstance *instance = [WXSDKManager instanceForID:instanceId]; |
| if (!instance) { |
| break; |
| } |
| if (!ref || !method) { |
| break; |
| } |
| NSString *componentRef = [NSString stringWithUTF8String:ref]; |
| NSString *methodName = [NSString stringWithUTF8String:method]; |
| NSArray *newArguments; |
| if (args && args_length > 0) { |
| NSString *arguments = [NSString stringWithUTF8String:args]; |
| newArguments = [WXUtility objectFromJSON:arguments]; |
| } |
| WXComponentMethod *method = [[WXComponentMethod alloc] initWithComponentRef:componentRef methodName:methodName arguments:newArguments instance:instance]; |
| [method invoke]; |
| |
| } while (0); |
| } |
| |
| void IOSSide::SetTimeout(const char* callbackID, const char* time) |
| { |
| // should not enter this function |
| assert(false); //!OCLint |
| } |
| |
| void IOSSide::NativeLog(const char *args) |
| { |
| // should not enter this function |
| do { |
| if (!args) { |
| break; |
| } |
| NSArray *newArguments; |
| if (args) { |
| NSString *arguments = [NSString stringWithUTF8String:args]; |
| newArguments = [WXUtility objectFromJSON:arguments]; |
| } |
| if (![newArguments isKindOfClass:[NSArray class]] || !newArguments.count) { |
| break; |
| } |
| static NSDictionary *levelMap; |
| static dispatch_once_t onceToken; |
| dispatch_once(&onceToken, ^{ |
| levelMap = @{@"__ERROR": @(WXLogFlagError), |
| @"__WARN": @(WXLogFlagWarning), |
| @"__INFO": @(WXLogFlagInfo), |
| @"__DEBUG": @(WXLogFlagDebug), |
| @"__LOG": @(WXLogFlagLog)}; |
| }); |
| NSString *levelStr = [newArguments lastObject]; |
| consoleWithArguments(newArguments, (WXLogFlag)[levelMap[levelStr] integerValue]); |
| |
| } while (0); |
| } |
| |
| void IOSSide::TriggerVSync(const char* page_id) |
| { |
| RenderPageBase *page = RenderManager::GetInstance()->GetPage(page_id); |
| if (page == nullptr) { |
| return; |
| } |
| |
| NSString* ns_instanceId = NSSTRING(page_id); |
| WXComponentManager* manager = [WXSDKManager instanceForID:ns_instanceId].componentManager; |
| if (!manager.isValid) { |
| return; |
| } |
| [manager startComponentTasks]; |
| } |
| |
| int IOSSide::UpdateFinish(const char* page_id, const char* task, int taskLen, |
| const char* callback, int callbackLen) |
| { |
| RenderPageBase *page = RenderManager::GetInstance()->GetPage(page_id); |
| if (page == nullptr) { |
| return -1; |
| } |
| |
| NSString* ns_instanceId = NSSTRING(page_id); |
| WXComponentManager* manager = [WXSDKManager instanceForID:ns_instanceId].componentManager; |
| if (!manager.isValid) { |
| return -1; |
| } |
| [manager startComponentTasks]; |
| [manager updateFinish]; |
| |
| return 0; |
| } |
| |
| int IOSSide::RefreshFinish(const char* pageId, const char *task, const char *callback) |
| { |
| RenderPageBase *page = RenderManager::GetInstance()->GetPage(pageId); |
| if (page == nullptr) { |
| return -1; |
| } |
| |
| NSString* ns_instanceId = NSSTRING(pageId); |
| WXComponentManager* manager = [WXSDKManager instanceForID:ns_instanceId].componentManager; |
| if (!manager.isValid) { |
| return -1; |
| } |
| [manager startComponentTasks]; |
| [manager refreshFinish]; |
| |
| return 0; |
| } |
| |
| int IOSSide::AddEvent(const char* pageId, const char* ref, const char *event) |
| { |
| RenderPageBase *page = RenderManager::GetInstance()->GetPage(pageId); |
| if (page == nullptr) { |
| return -1; |
| } |
| |
| long long startTime = getCurrentTime(); |
| |
| NSString* ns_instanceId = NSSTRING(pageId); |
| NSString* ns_ref = NSSTRING(ref); |
| NSString* ns_event = NSSTRING(event); |
| |
| #ifdef DEBUG |
| WXLogDebug(@"flexLayout -> action: addEvent ref:%@", ns_ref); |
| #endif |
| |
| WXComponentManager *manager = [WXSDKManager instanceForID:ns_instanceId].componentManager; |
| if (!manager.isValid) { |
| return -1; |
| } |
| [manager startComponentTasks]; |
| [manager addEvent:ns_event toComponent:ns_ref]; |
| |
| page->CallBridgeTime(getCurrentTime() - startTime); |
| return 0; |
| } |
| |
| int IOSSide::RemoveEvent(const char* pageId, const char* ref, const char *event) |
| { |
| RenderPageBase *page = RenderManager::GetInstance()->GetPage(pageId); |
| if (page == nullptr) { |
| return -1; |
| } |
| |
| long long startTime = getCurrentTime(); |
| |
| NSString* ns_instanceId = NSSTRING(pageId); |
| NSString* ns_ref = NSSTRING(ref); |
| NSString* ns_event = NSSTRING(event); |
| |
| #ifdef DEBUG |
| WXLogDebug(@"flexLayout -> action :removeEvent ref:%@", ns_ref); |
| #endif |
| |
| WXComponentManager* manager = [WXSDKManager instanceForID:ns_instanceId].componentManager; |
| if (!manager.isValid) { |
| return -1; |
| } |
| [manager startComponentTasks]; |
| [manager removeEvent:ns_event fromComponent:ns_ref]; |
| |
| page->CallBridgeTime(getCurrentTime() - startTime); |
| return 0; |
| } |
| |
| int IOSSide::CreateBody(const char* pageId, const char *componentType, const char* ref, |
| std::map<std::string, std::string> *styles, |
| std::map<std::string, std::string> *attributes, |
| std::set<std::string> *events, |
| const WXCoreMargin &margins, |
| const WXCorePadding &paddings, |
| const WXCoreBorderWidth &borders) |
| { |
| RenderPageBase *page = RenderManager::GetInstance()->GetPage(pageId); |
| if (page == nullptr) { |
| return -1; |
| } |
| |
| long long startTime = getCurrentTime(); |
| |
| RenderObject* renderObject = page->GetRenderObject(ref); |
| |
| NSString* ns_instanceId = NSSTRING(pageId); |
| NSString* ns_ref = NSSTRING(ref); |
| NSString* ns_type = NSSTRING(componentType); |
| NSMutableDictionary* ns_styles = NSDICTIONARY(styles); |
| NSDictionary* ns_attributes = NSDICTIONARY(attributes); |
| NSArray* ns_events = NSARRAY(events); |
| |
| WXSDKInstance* sdkInstance = [WXSDKManager instanceForID:ns_instanceId]; |
| MergeBorderWidthValues(ns_styles, borders, false, sdkInstance.pixelScaleFactor); |
| |
| #ifdef DEBUG |
| WXLogDebug(@"flexLayout -> action: createBody %@ ref:%@", ns_type, ns_ref); |
| #endif |
| |
| WXComponentManager* manager = sdkInstance.componentManager; |
| if (!manager.isValid) { |
| return -1; |
| } |
| [manager startComponentTasks]; |
| [manager createBody:ns_ref type:ns_type styles:ns_styles attributes:ns_attributes events:ns_events renderObject:renderObject]; |
| |
| page->CallBridgeTime(getCurrentTime() - startTime); |
| return 0; |
| } |
| |
| int IOSSide::AddElement(const char* pageId, const char *componentType, const char* ref, |
| int &index, const char* parentRef, |
| std::map<std::string, std::string> *styles, |
| std::map<std::string, std::string> *attributes, |
| std::set<std::string> *events, |
| const WXCoreMargin &margins, |
| const WXCorePadding &paddings, |
| const WXCoreBorderWidth &borders, |
| bool willLayout) |
| { |
| RenderPageBase *page = RenderManager::GetInstance()->GetPage(pageId); |
| if (page == nullptr) { |
| return -1; |
| } |
| |
| long long startTime = getCurrentTime(); |
| |
| RenderObject* renderObject = page->GetRenderObject(ref); |
| |
| NSString* ns_instanceId = NSSTRING(pageId); |
| NSString* ns_componentType = NSSTRING(componentType); |
| NSString* ns_ref = NSSTRING(ref); |
| NSString* ns_parentRef = NSSTRING(parentRef); |
| NSMutableDictionary* ns_styles = NSDICTIONARY(styles); |
| NSDictionary* ns_attributes = NSDICTIONARY(attributes); |
| NSArray* ns_events = NSARRAY(events); |
| NSInteger ns_index = index; |
| |
| WXSDKInstance* sdkInstance = [WXSDKManager instanceForID:ns_instanceId]; |
| MergeBorderWidthValues(ns_styles, borders, false, sdkInstance.pixelScaleFactor); |
| |
| #ifdef DEBUG |
| WXLogDebug(@"flexLayout -> action: addElement : %@", ns_componentType); |
| #endif |
| |
| WXComponentManager* manager = sdkInstance.componentManager; |
| if (!manager.isValid) { |
| return -1; |
| } |
| |
| [manager startComponentTasks]; |
| [manager addComponent:ns_ref type:ns_componentType parentRef:ns_parentRef styles:ns_styles attributes:ns_attributes events:ns_events index:ns_index renderObject:renderObject]; |
| |
| page->CallBridgeTime(getCurrentTime() - startTime); |
| return 0; |
| } |
| |
| int IOSSide::AddChildToRichtext(const char* pageId, const char *nodeType, const char* ref, |
| const char* parentRef, const char* richtextRef, |
| std::map<std::string, std::string> *styles, |
| std::map<std::string, std::string> *attributes) |
| { |
| RenderPageBase *page = RenderManager::GetInstance()->GetPage(pageId); |
| if (page == nullptr) { |
| return -1; |
| } |
| NSString* ns_richtextRef = NSSTRING(richtextRef); |
| NSString* ns_instanceId = NSSTRING(pageId); |
| NSString* ns_nodeType = NSSTRING(nodeType); |
| NSString* ns_ref = NSSTRING(ref); |
| NSString* ns_parentRef = NSSTRING(parentRef); |
| NSMutableDictionary* ns_styles = NSDICTIONARY(styles); |
| NSDictionary* ns_attributes = NSDICTIONARY(attributes); |
| |
| WXSDKInstance* sdkInstance = [WXSDKManager instanceForID:ns_instanceId]; |
| WXComponentManager* manager = sdkInstance.componentManager; |
| if (!manager.isValid) { |
| return -1; |
| } |
| |
| WXRichText* richtext = (WXRichText*)[manager componentForRef:ns_richtextRef]; |
| [richtext addChildNode:ns_nodeType ref:ns_ref styles:ns_styles attributes:ns_attributes toSuperNodeRef:ns_parentRef]; |
| return 0; |
| } |
| |
| int IOSSide::Layout(const char* pageId, const char* ref, |
| float top, float bottom, float left, float right, |
| float height, float width, bool isRTL, int index) |
| { |
| RenderPageBase *page = RenderManager::GetInstance()->GetPage(pageId); |
| if (page == nullptr) { |
| return -1; |
| } |
| |
| long long startTime = getCurrentTime(); |
| |
| RenderObject* renderObject = page->GetRenderObject(ref); |
| if (renderObject->getContext() == nullptr) { |
| return -1; |
| } |
| WXComponent* component = (__bridge WXComponent *)(renderObject->getContext()); |
| NSString* ns_instanceId = NSSTRING(pageId); |
| |
| WXComponentManager* manager = [WXSDKManager instanceForID:ns_instanceId].componentManager; |
| if (!manager.isValid) { |
| return -1; |
| } |
| CGRect frame = CGRectMake(isnan(WXCeilPixelValue(left))?0:WXCeilPixelValue(left), |
| isnan(WXCeilPixelValue(top))?0:WXCeilPixelValue(top), |
| isnan(WXCeilPixelValue(width))?0:WXCeilPixelValue(width), |
| isnan(WXCeilPixelValue(height))?0:WXCeilPixelValue(height)); |
| [manager layoutComponent:component frame:frame isRTL:isRTL innerMainSize:renderObject->getLargestMainSize()]; |
| |
| page->CallBridgeTime(getCurrentTime() - startTime); |
| return 0; |
| } |
| |
| void IOSSide::InvokeLayoutPlatform(const char* page_id, long render_ptr) |
| { |
| RenderPageBase *page = RenderManager::GetInstance()->GetPage(page_id); |
| if (page == nullptr) { |
| return; |
| } |
| |
| long long startTime = getCurrentTime(); |
| |
| RenderObject* renderObject = reinterpret_cast<RenderObject*>(render_ptr); |
| if (renderObject->getContext() == nullptr) { |
| return; |
| } |
| WXComponent* component = (__bridge WXComponent *)(renderObject->getContext()); |
| NSString* ns_instanceId = NSSTRING(page_id); |
| |
| WXComponentManager* manager = [WXSDKManager instanceForID:ns_instanceId].componentManager; |
| if (!manager.isValid) { |
| return; |
| } |
| |
| [manager layoutComponent:component]; |
| |
| page->CallBridgeTime(getCurrentTime() - startTime); |
| } |
| |
| int IOSSide::UpdateRichtextStyle(const char* pageId, const char* ref, |
| std::vector<std::pair<std::string, std::string>> *style, |
| const char* parent_ref, const char* richtext_ref) |
| { |
| RenderPageBase *page = RenderManager::GetInstance()->GetPage(pageId); |
| if (page == nullptr) { |
| return -1; |
| } |
| |
| NSString* ns_instanceId = NSSTRING(pageId); |
| NSString* ns_ref = NSSTRING(ref); |
| NSString* ns_richtextRef = NSSTRING(richtext_ref); |
| NSString* ns_parentRef = NSSTRING(parent_ref); |
| NSMutableDictionary* ns_style = NSDICTIONARY(style); |
| |
| WXSDKInstance* sdkInstance = [WXSDKManager instanceForID:ns_instanceId]; |
| if (!sdkInstance) { |
| return -1; |
| } |
| WXComponentManager* manager = sdkInstance.componentManager; |
| if (!manager.isValid) { |
| return -1; |
| } |
| |
| WXRichText* richtext = (WXRichText*)[manager componentForRef:ns_richtextRef]; |
| [richtext updateChildNodeStyles:ns_style ref:ns_ref parentRef:ns_parentRef]; |
| return 0; |
| } |
| |
| int IOSSide::UpdateStyle(const char* pageId, const char* ref, |
| std::vector<std::pair<std::string, std::string>> *style, |
| std::vector<std::pair<std::string, std::string>> *margin, |
| std::vector<std::pair<std::string, std::string>> *padding, |
| std::vector<std::pair<std::string, std::string>> *border) |
| { |
| RenderPageBase *page = RenderManager::GetInstance()->GetPage(pageId); |
| if (page == nullptr) { |
| return -1; |
| } |
| |
| long long startTime = getCurrentTime(); |
| |
| NSString* ns_instanceId = NSSTRING(pageId); |
| NSString* ns_ref = NSSTRING(ref); |
| NSMutableDictionary* ns_style = NSDICTIONARY(style); |
| |
| WXSDKInstance* sdkInstance = [WXSDKManager instanceForID:ns_instanceId]; |
| MergeBorderWidthValues(ns_style, border, sdkInstance.pixelScaleFactor); |
| |
| #ifdef DEBUG |
| WXLogDebug(@"flexLayout -> action: updateStyles ref:%@, styles:%@", ns_ref, ns_style); |
| #endif |
| |
| WXComponentManager* manager = sdkInstance.componentManager; |
| if (!manager.isValid) { |
| return -1; |
| } |
| |
| [manager startComponentTasks]; |
| [manager updateStyles:ns_style forComponent:ns_ref]; |
| |
| page->CallBridgeTime(getCurrentTime() - startTime); |
| return 0; |
| } |
| |
| int IOSSide::UpdateAttr(const char* pageId, const char* ref, |
| std::vector<std::pair<std::string, std::string>> *attrs) |
| { |
| if (attrs == nullptr) { |
| return 0; |
| } |
| if (attrs->size() == 0) { |
| return 0; |
| } |
| |
| RenderPageBase *page = RenderManager::GetInstance()->GetPage(pageId); |
| if (page == nullptr) { |
| return -1; |
| } |
| |
| long long startTime = getCurrentTime(); |
| |
| NSString* ns_instanceId = NSSTRING(pageId); |
| NSString* ns_ref = NSSTRING(ref); |
| NSDictionary* ns_attributes = NSDICTIONARY(attrs); |
| |
| #ifdef DEBUG |
| WXLogDebug(@"flexLayout -> action: updateAttrs ref:%@, attr:%@", ns_ref, ns_attributes); |
| #endif |
| |
| WXComponentManager* manager = [WXSDKManager instanceForID:ns_instanceId].componentManager; |
| if (!manager.isValid) { |
| return -1; |
| } |
| [manager startComponentTasks]; |
| [manager updateAttributes:ns_attributes forComponent:ns_ref]; |
| |
| page->CallBridgeTime(getCurrentTime() - startTime); |
| return 0; |
| } |
| |
| int IOSSide::UpdateRichtextChildAttr(const char* pageId, const char* ref, |
| std::vector<std::pair<std::string, std::string>> *attrs, const char* parent_ref, const char* richtext_ref) |
| { |
| RenderPageBase *page = RenderManager::GetInstance()->GetPage(pageId); |
| if (page == nullptr) { |
| return -1; |
| } |
| if (attrs == nullptr) { |
| return 0; |
| } |
| if (attrs->size() == 0) { |
| return 0; |
| } |
| |
| NSString* ns_instanceId = NSSTRING(pageId); |
| NSString* ns_ref = NSSTRING(ref); |
| NSString* ns_parentRef = NSSTRING(parent_ref); |
| NSString* ns_richtextRef = NSSTRING(richtext_ref); |
| NSDictionary* ns_attributes = NSDICTIONARY(attrs); |
| WXSDKInstance* sdkInstance = [WXSDKManager instanceForID:ns_instanceId]; |
| if (!sdkInstance) { |
| return -1; |
| } |
| WXComponentManager* manager = sdkInstance.componentManager; |
| if (!manager.isValid) { |
| return -1; |
| } |
| |
| WXRichText* richtext = (WXRichText*)[manager componentForRef:ns_richtextRef]; |
| [richtext updateChildNodeAttributes:ns_attributes ref:ns_ref parentRef:ns_parentRef]; |
| return 0; |
| } |
| |
| int IOSSide::CreateFinish(const char* pageId) |
| { |
| RenderPageBase *page = RenderManager::GetInstance()->GetPage(pageId); |
| |
| long long startTime = getCurrentTime(); |
| |
| NSString* ns_instanceId = NSSTRING(pageId); |
| |
| #ifdef DEBUG |
| WXLogDebug(@"flexLayout -> action: createFinish :%@", ns_instanceId); |
| #endif |
| |
| WXComponentManager* manager = [WXSDKManager instanceForID:ns_instanceId].componentManager; |
| if (!manager.isValid) { |
| return -1; |
| } |
| [manager startComponentTasks]; |
| [manager createFinish]; |
| |
| if (page) { |
| page->CallBridgeTime(getCurrentTime() - startTime); |
| } |
| return 0; |
| } |
| |
| int IOSSide::RenderSuccess(const char* pageId) |
| { |
| RenderPageBase *page = RenderManager::GetInstance()->GetPage(pageId); |
| |
| long long startTime = getCurrentTime(); |
| |
| NSString* ns_instanceId = NSSTRING(pageId); |
| |
| #ifdef DEBUG |
| WXLogDebug(@"flexLayout -> action: renderFinish :%@", ns_instanceId); |
| #endif |
| |
| WXComponentManager* manager = [WXSDKManager instanceForID:ns_instanceId].componentManager; |
| if (!manager.isValid) { |
| return -1; |
| } |
| [manager startComponentTasks]; |
| [manager renderFinish]; |
| |
| if (page) { |
| page->CallBridgeTime(getCurrentTime() - startTime); |
| } |
| return 0; |
| } |
| |
| int IOSSide::RemoveChildFromRichtext(const char* pageId, const char* ref, const char* parent_ref, const char* richtext_ref) { |
| RenderPageBase *page = RenderManager::GetInstance()->GetPage(pageId); |
| if (page == nullptr) { |
| return -1; |
| } |
| |
| NSString* ns_instanceId = NSSTRING(pageId); |
| NSString* ns_richtextRef = NSSTRING(richtext_ref); |
| NSString* ns_ref = NSSTRING(ref); |
| NSString* ns_parentRef = NSSTRING(parent_ref); |
| |
| WXSDKInstance* sdkInstance = [WXSDKManager instanceForID:ns_instanceId]; |
| WXComponentManager* manager = sdkInstance.componentManager; |
| if (!manager.isValid) { |
| return -1; |
| } |
| |
| WXRichText* richtext = (WXRichText*)[manager componentForRef:ns_richtextRef]; |
| [richtext removeChildNode:ns_ref superNodeRef:ns_parentRef]; |
| return 0; |
| } |
| int IOSSide::RemoveElement(const char* pageId, const char* ref) |
| { |
| RenderPageBase *page = RenderManager::GetInstance()->GetPage(pageId); |
| if (page == nullptr) { |
| return -1; |
| } |
| |
| long long startTime = getCurrentTime(); |
| |
| NSString* ns_instanceId = NSSTRING(pageId); |
| NSString* ns_ref = NSSTRING(ref); |
| |
| #ifdef DEBUG |
| WXLogDebug(@"flexLayout -> action: removeElement ref:%@", ns_ref); |
| #endif |
| |
| WXComponentManager* manager = [WXSDKManager instanceForID:ns_instanceId].componentManager; |
| if (!manager.isValid) { |
| return -1; |
| } |
| |
| [manager startComponentTasks]; |
| [manager removeComponent:ns_ref]; |
| |
| page->CallBridgeTime(getCurrentTime() - startTime); |
| return 0; |
| } |
| |
| int IOSSide::MoveElement(const char* pageId, const char* ref, const char* parentRef, int index) |
| { |
| RenderPageBase *page = RenderManager::GetInstance()->GetPage(pageId); |
| if (page == nullptr) { |
| return -1; |
| } |
| |
| long long startTime = getCurrentTime(); |
| |
| NSString* ns_instanceId = NSSTRING(pageId); |
| NSString* ns_ref = NSSTRING(ref); |
| NSString* ns_parentRef = NSSTRING(parentRef); |
| NSInteger ns_index = index; |
| |
| #ifdef DEBUG |
| WXLogDebug(@"flexLayout -> action: moveElement, ref:%@ to ref:%@", ns_ref, ns_parentRef); |
| #endif |
| |
| WXComponentManager* manager = [WXSDKManager instanceForID:ns_instanceId].componentManager; |
| if (!manager.isValid) { |
| return -1; |
| } |
| |
| [manager startComponentTasks]; |
| [manager moveComponent:ns_ref toSuper:ns_parentRef atIndex:ns_index]; |
| |
| page->CallBridgeTime(getCurrentTime() - startTime); |
| return 0; |
| } |
| |
| int IOSSide::AppendTreeCreateFinish(const char* pageId, const char* ref) |
| { |
| RenderPageBase *page = RenderManager::GetInstance()->GetPage(pageId); |
| if (page == nullptr) { |
| return -1; |
| } |
| |
| long long startTime = getCurrentTime(); |
| |
| NSString* ns_instanceId = NSSTRING(pageId); |
| NSString* ns_ref = NSSTRING(ref); |
| |
| WXComponentManager* manager = [WXSDKManager instanceForID:ns_instanceId].componentManager; |
| if (!manager.isValid) { |
| return -1; |
| } |
| [manager startComponentTasks]; |
| [manager appendTreeCreateFinish:ns_ref]; |
| |
| page->CallBridgeTime(getCurrentTime() - startTime); |
| return 0; |
| } |
| |
| int IOSSide::HasTransitionPros(const char* pageId, const char* ref, |
| std::vector<std::pair<std::string, std::string>> *style) |
| { |
| RenderPageBase *page = RenderManager::GetInstance()->GetPage(pageId); |
| if (page == nullptr) { |
| return -1; |
| } |
| |
| long long startTime = getCurrentTime(); |
| |
| NSString* ns_instanceId = NSSTRING(pageId); |
| NSString* ns_ref = NSSTRING(ref); |
| |
| WXComponentManager* manager = [WXSDKManager instanceForID:ns_instanceId].componentManager; |
| if (!manager.isValid) { |
| return -1; |
| } |
| |
| // if transition is none, return directly, avoiding convert style |
| if ([manager isTransitionNoneOfComponent:ns_ref]) { |
| return 0; |
| } |
| |
| int result = [manager hasTransitionPropertyInStyles:NSDICTIONARY(style) forComponent:ns_ref] ? 1 : 0; |
| |
| page->CallBridgeTime(getCurrentTime() - startTime); |
| return result; |
| } |
| |
| void IOSSide::PostTaskOnComponentThread(const weex::base::Closure closure) { |
| WXPerformBlockOnComponentThread(^{ |
| closure(); |
| }); |
| } |
| |
| #pragma mark - Layout Impl |
| |
| WXCoreSize WXCoreMeasureFunctionBridge::Measure(const char* page_id, long render_ptr, float width, MeasureMode widthMeasureMode, float height, MeasureMode heightMeasureMode) |
| { |
| // should not enter this function |
| assert(false); //!OCLint |
| } |
| |
| void WXCoreMeasureFunctionBridge::LayoutBefore(const char* page_id, long render_ptr) |
| { |
| |
| } |
| |
| void WXCoreMeasureFunctionBridge::LayoutAfter(const char* page_id, long render_ptr, float width, float height) |
| { |
| |
| } |
| |
| #pragma mark - Log Bridge |
| |
| class LogBridgeIOS: public weex::base::LogBase { |
| public: |
| virtual bool log(LogLevel level, const char* tag, const char* file, unsigned long line, const char* log) override { |
| #ifdef DEBUG |
| switch (level) { |
| case LogLevel::Error: |
| printf("<%s:Error|%s:%lu> %s\n", tag, file, line, log); |
| break; |
| case LogLevel::Warn: |
| printf("<%s:Warn|%s:%lu> %s\n", tag, file, line, log); |
| break; |
| case LogLevel::Info: |
| printf("<%s:Info|%s:%lu> %s\n", tag, file, line, log); |
| break; |
| case LogLevel::Debug: |
| printf("<%s:Debug|%s:%lu> %s\n", tag, file, line, log); |
| break; |
| default: |
| break; |
| } |
| #else |
| WXLogFlag wxLogLevel; |
| switch (level) { |
| case LogLevel::Error: |
| wxLogLevel = WXLogFlagError; |
| break; |
| case LogLevel::Warn: |
| wxLogLevel = WXLogFlagWarning; |
| break; |
| case LogLevel::Info: |
| wxLogLevel = WXLogFlagInfo; |
| break; |
| default: |
| wxLogLevel = WXLogFlagDebug; |
| break; |
| } |
| |
| [WXLog devLog:wxLogLevel file:file line:line format:@"<%s> %s", tag, log]; |
| #endif |
| return true; |
| } |
| }; |
| } |
| |
| @interface WXCustomPageBridge() |
| { |
| std::mutex _customPageLock; |
| std::map<std::string, WeexCore::RenderPageCustom*> _customPages; |
| |
| WeexCore::RenderPageCustom* _lastPage; |
| } |
| |
| @end |
| |
| @implementation WXCustomPageBridge |
| |
| + (instancetype)sharedInstance |
| { |
| static dispatch_once_t onceToken; |
| static WXCustomPageBridge* instance; |
| dispatch_once(&onceToken, ^{ |
| instance = [[WXCustomPageBridge alloc] init]; |
| }); |
| return instance; |
| } |
| |
| + (BOOL)isCustomPage:(NSString*)pageId |
| { |
| return [pageId integerValue] % 2 != 0; |
| } |
| |
| + (NSSet<NSString*>*)getAvailableCustomRenderTypes |
| { |
| NSMutableSet<NSString*>* result = [[NSMutableSet alloc] init]; |
| for (const std::string& s : WeexCore::RenderTargetManager::sharedInstance()->getAvailableTargetNames()) { |
| [result addObject:NSSTRING(s.c_str())]; |
| } |
| return result; |
| } |
| |
| + (UIView*)createPageRootView:(NSString*)pageId pageType:(NSString*)pageType frame:(CGRect)frame |
| { |
| auto target = WeexCore::RenderTargetManager::sharedInstance()->getRenderTarget([pageType UTF8String]?:""); |
| if (target) { |
| return (__bridge UIView*)((void*)(target->createRootView([pageId UTF8String]?:"", frame.origin.x, frame.origin.y, frame.size.width, frame.size.height))); |
| } |
| return nil; |
| } |
| |
| + (void)parseRenderObject:(NSDictionary *)data |
| parentRef:(const std::string&)parentRef |
| index:(int)index |
| genObject:(void(^)(const std::string& ref, |
| const std::string& type, |
| const std::string& parentRef, |
| std::map<std::string, std::string>* styles, |
| std::map<std::string, std::string>* attrs, |
| std::set<std::string>* events, |
| int index))onGenObject |
| { |
| const char* type = [data[@"type"] UTF8String]; |
| const char* ref = [data[@"ref"] UTF8String]; |
| if (type != nullptr && ref != nullptr) { |
| std::map<std::string, std::string>* styles = new std::map<std::string, std::string>(); |
| std::map<std::string, std::string>* attrs = new std::map<std::string, std::string>(); |
| std::set<std::string>* events = new std::set<std::string>(); |
| |
| [data[@"attr"] enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) { |
| ConvertToCString(obj, ^(const char * value) { |
| if (value != nullptr) { |
| (*attrs)[[key UTF8String]] = value; |
| } |
| }); |
| }]; |
| |
| [data[@"style"] enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) { |
| ConvertToCString(obj, ^(const char * value) { |
| if (value != nullptr) { |
| (*styles)[[key UTF8String]] = value; |
| } |
| }); |
| }]; |
| |
| for (id obj in data[@"event"]) { |
| ConvertToCString(obj, ^(const char * value) { |
| if (value != nullptr) { |
| events->insert(value); |
| } |
| }); |
| } |
| |
| std::string thisRef = ref; |
| std::string thisType = type; |
| onGenObject(thisRef, thisType, parentRef, styles, attrs, events, index); |
| |
| // parse children |
| int childIndex = 0; |
| for (NSDictionary* obj in data[@"children"]) { |
| [self parseRenderObject:obj parentRef:thisRef index:childIndex ++ genObject:onGenObject]; |
| } |
| } |
| } |
| |
| + (std::vector<std::pair<std::string, std::string>>*)parseMapValuePairs:(NSDictionary *)data |
| { |
| std::vector<std::pair<std::string, std::string>>* result = new std::vector<std::pair<std::string, std::string>>(); |
| [data enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) { |
| ConvertToCString(obj, ^(const char * value) { |
| if (value != nullptr) { |
| result->emplace_back([key UTF8String], value); |
| } |
| }); |
| }]; |
| return result; |
| } |
| |
| - (WeexCore::RenderPageCustom*)getPage:(NSString*)pageId |
| { |
| std::lock_guard<std::mutex> lockGuard(_customPageLock); |
| std::string sId = [pageId UTF8String] ?: ""; |
| if (_lastPage && _lastPage->page_id() == sId) { |
| // avoid a map search |
| return _lastPage; |
| } |
| auto findPage = _customPages.find([pageId UTF8String] ?: ""); |
| _lastPage = findPage == _customPages.end() ? nullptr : findPage->second; |
| return _lastPage; |
| } |
| |
| - (void)invalidatePage:(NSString*)pageId |
| { |
| std::lock_guard<std::mutex> lockGuard(_customPageLock); |
| auto findPage = _customPages.find([pageId UTF8String] ?: ""); |
| if (findPage != _customPages.end()) { |
| findPage->second->Invalidate(); |
| } |
| } |
| |
| - (void)removePage:(NSString*)pageId |
| { |
| RenderPageCustom* thePage = nullptr; |
| { |
| std::lock_guard<std::mutex> lockGuard(_customPageLock); |
| auto findPage = _customPages.find([pageId UTF8String] ?: ""); |
| if (findPage != _customPages.end()) { |
| thePage = findPage->second; |
| _customPages.erase(findPage); |
| } |
| } |
| |
| if (thePage) { |
| thePage->OnRenderPageClose(); |
| delete thePage; |
| _lastPage = nullptr; |
| } |
| } |
| |
| - (void)callCreateBody:(NSString*)pageId data:(NSDictionary*)data |
| { |
| using namespace WeexCore; |
| |
| WXSDKInstance* sdkInstance = [WXSDKManager instanceForID:pageId]; |
| WXComponentManager* manager = sdkInstance.componentManager; |
| if (!manager.isValid) { |
| return; |
| } |
| |
| std::string sId = [pageId UTF8String] ?: ""; |
| if (sId.empty()) { |
| return; |
| } |
| |
| auto pageArgs = RenderManager::GetInstance()->removePageArguments(sId); |
| RenderPageCustom::PageOptions options; |
| |
| options.is_round_off = false; |
| options.view_scale = 1; |
| auto value = WXCoreEnvironment::getInstance()->GetOption("pixel_scale"); |
| if (value != "") { |
| options.view_scale = strtof(value.c_str(), NULL); |
| } |
| |
| auto findViewPort = pageArgs.find("viewportwidth"); |
| if (findViewPort != pageArgs.end()) { |
| options.viewport_width = strtof(findViewPort->second.c_str(), nullptr); |
| } |
| else { |
| options.viewport_width = kDefaultViewPortWidth; |
| } |
| |
| auto findDeviceWidth = pageArgs.find("devicewidth"); |
| if (findDeviceWidth != pageArgs.end()) { |
| options.device_width = strtof(findDeviceWidth->second.c_str(), nullptr); |
| } |
| else { |
| /* For iOS DeviceWidth stored by WeexCore is in UIKit view system coordinate(iPhone6 is 375). |
| So we must provide heron with the pixel device width here. */ |
| options.device_width = WXCoreEnvironment::getInstance()->DeviceWidth() * options.view_scale; |
| } |
| |
| std::swap(options.args, pageArgs); |
| |
| RenderPageCustom* page = new RenderPageCustom(sId, "heron", options); |
| |
| { |
| std::lock_guard<std::mutex> lockGuard(_customPageLock); |
| _customPages[sId] = page; |
| } |
| |
| SetConvertCurrentPage(pageId); |
| [WXCustomPageBridge parseRenderObject:data parentRef:"" index:0 genObject:^(const std::string &ref, const std::string &type, const std::string &parentRef, std::map<std::string, std::string> *styles, std::map<std::string, std::string> *attrs, std::set<std::string> *events, int index) { |
| if (parentRef.empty()) { |
| // is root body |
| page->CreateBody(ref, type, styles, attrs, events); |
| } |
| else { |
| page->AddRenderObject(ref, type, parentRef, index, styles, attrs, events); |
| } |
| }]; |
| } |
| |
| - (void)callAddElement:(NSString*)pageId parentRef:(NSString*)parentRef data:(NSDictionary*)data index:(int)index |
| { |
| RenderPageCustom* page = [self getPage:pageId]; |
| if (page && page->IsValid()) { |
| [WXCustomPageBridge parseRenderObject:data parentRef:[parentRef UTF8String] ?: "" index:index genObject:^(const std::string &ref, const std::string &type, const std::string &parentRef, std::map<std::string, std::string> *styles, std::map<std::string, std::string> *attrs, std::set<std::string> *events, int index) { |
| page->AddRenderObject(ref, type, parentRef, index, styles, attrs, events); |
| }]; |
| } |
| } |
| |
| - (void)callRemoveElement:(NSString*)pageId ref:(NSString*)ref |
| { |
| RenderPageCustom* page = [self getPage:pageId]; |
| if (page && page->IsValid()) { |
| page->RemoveRenderObject([ref UTF8String] ?: ""); |
| } |
| } |
| |
| - (void)callMoveElement:(NSString*)pageId ref:(NSString*)ref parentRef:(NSString*)parentRef index:(int)index |
| { |
| RenderPageCustom* page = [self getPage:pageId]; |
| if (page && page->IsValid()) { |
| page->MoveRenderObject([ref UTF8String] ?: "", [parentRef UTF8String] ?: "", index); |
| } |
| } |
| |
| - (void)callUpdateAttrs:(NSString*)pageId ref:(NSString*)ref data:(NSDictionary*)data |
| { |
| RenderPageCustom* page = [self getPage:pageId]; |
| if (page && page->IsValid()) { |
| SetConvertCurrentPage(pageId); |
| page->UpdateAttr([ref UTF8String] ?: "", [WXCustomPageBridge parseMapValuePairs:data]); |
| } |
| } |
| |
| - (void)callUpdateStyle:(NSString*)pageId ref:(NSString*)ref data:(NSDictionary*)data |
| { |
| RenderPageCustom* page = [self getPage:pageId]; |
| if (page && page->IsValid()) { |
| SetConvertCurrentPage(pageId); |
| page->UpdateStyle([ref UTF8String] ?: "", [WXCustomPageBridge parseMapValuePairs:data]); |
| } |
| } |
| |
| - (void)callAddEvent:(NSString*)pageId ref:(NSString*)ref event:(NSString*)event |
| { |
| RenderPageCustom* page = [self getPage:pageId]; |
| if (page && page->IsValid()) { |
| page->AddEvent([ref UTF8String] ?: "", [event UTF8String] ?: ""); |
| } |
| } |
| |
| - (void)callRemoveEvent:(NSString*)pageId ref:(NSString*)ref event:(NSString*)event |
| { |
| RenderPageCustom* page = [self getPage:pageId]; |
| if (page && page->IsValid()) { |
| page->RemoveEvent([ref UTF8String] ?: "", [event UTF8String] ?: ""); |
| } |
| } |
| |
| - (void)callCreateFinish:(NSString*)pageId |
| { |
| WXPerformBlockOnComponentThread(^{ |
| RenderPageCustom* page = [self getPage:pageId]; |
| if (page && page->IsValid()) { |
| page->CreateFinish(); |
| } |
| }); |
| } |
| |
| - (void)callRefreshFinish:(NSString*)pageId |
| { |
| // TODO, this may not be correct, for heron may also need to implement refresh finish. |
| WeexCore::WeexCoreManager::Instance()->script_bridge()->core_side()->RefreshFinish([pageId UTF8String] ?: "", nullptr, nullptr); |
| } |
| |
| - (void)callUpdateFinish:(NSString*)pageId |
| { |
| // TODO, this may not be correct, for heron may also need to implement update finish. |
| WeexCore::WeexCoreManager::Instance()->script_bridge()->core_side()->UpdateFinish([pageId UTF8String] ?: "", nullptr, 0, nullptr, 0); |
| } |
| |
| - (BOOL)forwardCallNativeModuleToCustomPage:(NSString*)pageId |
| moduleName:(NSString*)moduleName methodName:(NSString*)methodName |
| arguments:(NSArray*)arguments options:(NSDictionary*)options |
| returnValue:(id*)returnValue |
| { |
| using namespace WeexCore; |
| |
| RenderPageCustom* page = [self getPage:pageId]; |
| if (page && page->IsValid()) { |
| RenderTarget* target = page->GetRenderTarget(); |
| if (target && target->shouldHandleModuleMethod([moduleName UTF8String] ?: "", [methodName UTF8String] ?: "")) { |
| __block const char* seralizedArguments = nullptr; |
| __block const char* seralizedOptions = nullptr; |
| SetConvertCurrentPage(pageId); |
| ConvertToCString(arguments, ^(const char * value) { |
| if (value != nullptr) { |
| seralizedArguments = strdup(value); |
| } |
| }); |
| ConvertToCString(options, ^(const char * value) { |
| if (value != nullptr) { |
| seralizedOptions = strdup(value); |
| } |
| }); |
| |
| bool handled = false; |
| std::unique_ptr<ValueWithType> result = target->callNativeModule([pageId UTF8String] ?: "", [moduleName UTF8String] ?: "", [methodName UTF8String] ?: "", seralizedArguments ?: "", seralizedArguments ? (int)(strlen(seralizedArguments)) : 0, seralizedOptions ?: "", seralizedOptions ? (int)(strlen(seralizedOptions)) : 0, handled); |
| |
| if (seralizedArguments) { |
| free((void*)seralizedArguments); |
| } |
| if (seralizedOptions) { |
| free((void*)seralizedOptions); |
| } |
| |
| if (handled && result) { |
| switch (result->type) { |
| case ParamsType::INT32: |
| *returnValue = @(result->value.int32Value); |
| break; |
| case ParamsType::INT64: |
| *returnValue = @(result->value.int64Value); |
| break; |
| case ParamsType::FLOAT: |
| *returnValue = @(result->value.floatValue); |
| break; |
| case ParamsType::DOUBLE: |
| *returnValue = @(result->value.doubleValue); |
| break; |
| case ParamsType::JSONSTRING: |
| { |
| NSString* s = [NSString stringWithCharacters:(const unichar *)(result->value.string->content) length:result->value.string->length]; |
| free(result->value.string); |
| |
| @try { |
| NSError* error = nil; |
| id jsonObj = [NSJSONSerialization JSONObjectWithData:[s dataUsingEncoding:NSUTF8StringEncoding] |
| options:NSJSONReadingMutableContainers | NSJSONReadingMutableLeaves |
| error:&error]; |
| |
| if (jsonObj == nil) { |
| WXLogError(@"%@", error); |
| WXAssert(NO, @"Fail to convert json to object. %@", error); |
| } |
| else { |
| *returnValue = jsonObj; |
| } |
| } @catch (NSException *exception) { |
| WXLogError(@"%@", exception); |
| WXAssert(NO, @"Fail to convert json to object. %@", exception); |
| } |
| } |
| break; |
| case ParamsType::STRING: |
| *returnValue = [NSString stringWithCharacters:(const unichar *)(result->value.string->content) length:result->value.string->length]; |
| free(result->value.string); |
| break; |
| default: |
| *returnValue = nil; |
| break; |
| } |
| return YES; |
| } |
| } |
| } |
| |
| return NO; |
| } |
| |
| - (void)forwardCallComponentToCustomPage:(NSString*)pageId |
| ref:(NSString*)ref |
| methodName:(NSString*)methodName |
| arguments:(NSArray*)arguments |
| options:(NSDictionary*)options |
| { |
| using namespace WeexCore; |
| |
| RenderPageCustom* page = [self getPage:pageId]; |
| if (page && page->IsValid()) { |
| RenderTarget* target = page->GetRenderTarget(); |
| if (target) { |
| __block const char* seralizedArguments = nullptr; |
| __block const char* seralizedOptions = nullptr; |
| SetConvertCurrentPage(pageId); |
| ConvertToCString(arguments, ^(const char * value) { |
| if (value != nullptr) { |
| seralizedArguments = strdup(value); |
| } |
| }); |
| ConvertToCString(options, ^(const char * value) { |
| if (value != nullptr) { |
| seralizedOptions = strdup(value); |
| } |
| }); |
| |
| target->callNativeComponent([pageId UTF8String] ?: "", [ref UTF8String] ?: "", [methodName UTF8String] ?: "", seralizedArguments ?: "", seralizedArguments ? (int)(strlen(seralizedArguments)) : 0, seralizedOptions ?: "", seralizedOptions ? (int)(strlen(seralizedOptions)) : 0); |
| |
| if (seralizedArguments) { |
| free((void*)seralizedArguments); |
| } |
| if (seralizedOptions) { |
| free((void*)seralizedOptions); |
| } |
| } |
| } |
| } |
| |
| @end |
| |
| @implementation WXCoreBridge |
| |
| static WeexCore::PlatformBridge* platformBridge = nullptr; |
| static WeexCore::ScriptBridge* jsBridge = nullptr; |
| |
| + (void)install |
| { |
| static dispatch_once_t onceToken; |
| dispatch_once(&onceToken, ^{ |
| WeexCore::WXCoreEnvironment* env = WeexCore::WXCoreEnvironment::getInstance(); |
| env->SetPlatform(OS_iOS); |
| |
| /* For historical reason, layout in weexcore and layout result are in iOS UIView system unit. |
| So we pass 'scale' as 1 to affect nothing. |
| */ |
| env->AddOption("scale", "1"); |
| env->AddOption("pixel_scale", std::to_string([[UIScreen mainScreen] scale])); |
| |
| // Here we initialize weex device width and height using portrait by default. |
| CGSize screenSize = [UIScreen mainScreen].bounds.size; |
| CGFloat w = MIN(screenSize.width, screenSize.height); |
| CGFloat h = MAX(screenSize.width, screenSize.height); |
| env->SetDeviceWidth(std::to_string(w)); |
| env->SetDeviceHeight(std::to_string(h)); |
| env->AddOption("screen_width_pixels", std::to_string(w)); |
| env->AddOption("screen_height_pixels", std::to_string(h)); |
| |
| weex::base::LogImplement::getLog()->setLogImplement(new WeexCore::LogBridgeIOS()); |
| |
| #ifdef DEBUG |
| weex::base::LogImplement::getLog()->setDebugMode(true); |
| #else |
| weex::base::LogImplement::getLog()->setDebugMode(false); |
| #endif |
| |
| platformBridge = new WeexCore::PlatformBridge(); |
| platformBridge->set_platform_side(new WeexCore::IOSSide()); |
| platformBridge->set_core_side(new WeexCore::CoreSideInPlatform()); |
| WeexCore::WeexCoreManager::Instance()->set_platform_bridge(platformBridge); |
| |
| jsBridge = new WeexCore::ScriptBridge(); |
| jsBridge->set_core_side(new WeexCore::CoreSideInScript()); |
| WeexCore::WeexCoreManager::Instance()->set_script_bridge(jsBridge); |
| |
| WeexCore::WeexCoreManager::Instance()->set_measure_function_adapter(new WeexCore::WXCoreMeasureFunctionBridge()); |
| |
| [[WXSDKManager bridgeMgr] checkJSThread]; |
| }); |
| } |
| |
| + (void)registerComponentAffineType:(NSString *)type asType:(NSString *)baseType |
| { |
| WeexCore::RenderCreator::GetInstance()->RegisterAffineType([type UTF8String] ?: "", [baseType UTF8String] ?: ""); |
| } |
| |
| + (BOOL)isComponentAffineType:(NSString *)type asType:(NSString *)baseType |
| { |
| return WeexCore::RenderCreator::GetInstance()->IsAffineType([type UTF8String] ?: "", [baseType UTF8String] ?: ""); |
| } |
| |
| + (void)setDefaultDimensionIntoRoot:(NSString*)pageId width:(CGFloat)width height:(CGFloat)height |
| isWidthWrapContent:(BOOL)isWidthWrapContent |
| isHeightWrapContent:(BOOL)isHeightWrapContent |
| { |
| if (platformBridge) { |
| if (width == 0 && !isWidthWrapContent) { |
| return; |
| } |
| |
| if (height == 0 && !isHeightWrapContent) { |
| return; |
| } |
| |
| platformBridge->core_side()->SetDefaultHeightAndWidthIntoRootDom([pageId UTF8String] ?: "", (float)width, (float)height, (bool)isWidthWrapContent, (bool)isHeightWrapContent); |
| } |
| } |
| |
| + (void)setDeviceSize:(CGSize)size |
| { |
| [WXCoreBridge install]; |
| WeexCore::WXCoreEnvironment* env = WeexCore::WXCoreEnvironment::getInstance(); |
| env->SetDeviceWidth(std::to_string(size.width)); |
| env->SetDeviceHeight(std::to_string(size.height)); |
| } |
| |
| + (CGSize)getDeviceSize |
| { |
| [WXCoreBridge install]; |
| WeexCore::WXCoreEnvironment* env = WeexCore::WXCoreEnvironment::getInstance(); |
| return CGSizeMake(env->DeviceWidth(), env->DeviceHeight()); |
| } |
| |
| + (void)setViewportWidth:(NSString*)pageId width:(CGFloat)width |
| { |
| [WXCoreBridge install]; |
| if (platformBridge) { |
| platformBridge->core_side()->SetViewPortWidth([pageId UTF8String] ?: "", (float)width); |
| } |
| } |
| |
| + (void)setPageRequired:(NSString *)pageId width:(CGFloat)width height:(CGFloat)height |
| { |
| [WXCoreBridge install]; |
| if (platformBridge) { |
| platformBridge->core_side()->SetDeviceDisplayOfPage([pageId UTF8String] ?: "", (float)width, (float)height); |
| } |
| } |
| |
| + (void)layoutPage:(NSString*)pageId forced:(BOOL)forced |
| { |
| if (platformBridge) { |
| const char* page = [pageId UTF8String] ?: ""; |
| if (forced) { |
| platformBridge->core_side()->SetPageDirty(page); |
| } |
| |
| if (platformBridge->core_side()->NotifyLayout(page)) { |
| platformBridge->core_side()->ForceLayout(page); |
| } |
| } |
| } |
| |
| + (double)getLayoutTime:(NSString*)pageId { |
| if (platformBridge) { |
| const char* page = [pageId UTF8String] ?: ""; |
| return platformBridge->core_side()->GetLayoutTime(page); |
| } |
| return 0; |
| } |
| |
| + (void)closePage:(NSString*)pageId |
| { |
| if (platformBridge) { |
| platformBridge->core_side()->DestroyInstance([pageId UTF8String]); |
| platformBridge->core_side()->OnInstanceClose([pageId UTF8String] ?: ""); |
| } |
| } |
| |
| + (BOOL)reloadPageLayout:(NSString*)pageId |
| { |
| if (platformBridge) { |
| return platformBridge->core_side()->RelayoutUsingRawCssStyles([pageId UTF8String] ?: ""); |
| } |
| return false; |
| } |
| |
| + (void)_traverseTree:(WeexCore::RenderObject *)render index:(int)index pageId:(const char *)pageId |
| { |
| using namespace WeexCore; |
| if (render == nullptr) return; |
| |
| if (render->hasNewLayout()) { |
| /* do not call bridge->callLayout because render is not registered to page, so that |
| page->GetRenderObject will not give the correct object. */ |
| RenderPageBase *page = RenderManager::GetInstance()->GetPage(pageId); |
| if (page != nullptr) { |
| WXComponent* component = (__bridge WXComponent *)(render->getContext()); |
| NSString* ns_instanceId = NSSTRING(pageId); |
| |
| float top = render->getLayoutPositionTop(); |
| float left = render->getLayoutPositionLeft(); |
| float height = render->getLayoutHeight(); |
| float width = render->getLayoutWidth(); |
| BOOL isRTL = render->getLayoutDirectionFromPathNode() == WeexCore::kDirectionRTL; |
| WXComponentManager* manager = [WXSDKManager instanceForID:ns_instanceId].componentManager; |
| CGRect frame = CGRectMake(isnan(WXCeilPixelValue(left))?0:WXCeilPixelValue(left), |
| isnan(WXCeilPixelValue(top))?0:WXCeilPixelValue(top), |
| isnan(WXCeilPixelValue(width))?0:WXCeilPixelValue(width), |
| isnan(WXCeilPixelValue(height))?0:WXCeilPixelValue(height)); |
| [manager layoutComponent:component frame:frame isRTL:isRTL innerMainSize:render->getLargestMainSize()]; |
| } |
| render->setHasNewLayout(false); |
| } |
| |
| for (auto it = render->ChildListIterBegin(); it != render->ChildListIterEnd(); it ++) { |
| WeexCore::RenderObject *child = static_cast<WeexCore::RenderObject *>(*it); |
| if (child != nullptr) { |
| [self _traverseTree:child index:(int)(it - render->ChildListIterBegin()) pageId:pageId]; |
| } |
| } |
| } |
| |
| + (void)layoutRenderObject:(void*)object size:(CGSize)size page:(NSString*)pageId |
| { |
| using namespace WeexCore; |
| RenderObject* render = static_cast<RenderObject*>(object); |
| std::pair<float, float> renderPageSize(size.width, size.height); |
| |
| render->calculateLayout(renderPageSize); |
| [self _traverseTree:render index:0 pageId:[pageId UTF8String] ?: ""]; |
| } |
| |
| + (void*)copyRenderObject:(void*)source replacedRef:(NSString*)ref |
| { |
| using namespace WeexCore; |
| RenderObject* sourceObject = static_cast<RenderObject*>(source); |
| RenderObject* copyObject = static_cast<RenderObject*>(RenderCreator::GetInstance()->CreateRender(sourceObject->type(), sourceObject->ref())); |
| |
| copyObject->CopyFrom(sourceObject); |
| if (ref != nil) { |
| copyObject->set_ref([ref UTF8String] ?: ""); |
| } |
| |
| if (sourceObject->type() == kRenderCellSlot || sourceObject->type() == kRenderCell) { |
| RenderList* renderList = static_cast<RenderList*>(sourceObject->getParent()); |
| if (renderList != nullptr) { |
| renderList->AddCellSlotCopyTrack(copyObject); |
| } |
| } |
| return copyObject; |
| } |
| |
| + (void)addChildRenderObject:(void*)child toParent:(void*)parent |
| { |
| (static_cast<WeexCore::RenderObject*>(parent))->AddRenderObject(-1, (static_cast<WeexCore::RenderObject*>(child))); |
| } |
| |
| + (void)removeRenderObjectFromMap:(NSString*)pageId object:(void*)object |
| { |
| using namespace WeexCore; |
| RenderPage* page = static_cast<RenderPage*>(RenderManager::GetInstance()->GetPage([pageId UTF8String] ?: "")); |
| if (page != nullptr) { |
| page->RemoveRenderFromRegisterMap(static_cast<RenderObject*>(object)); |
| } |
| } |
| |
| + (void)_parseStyleBeforehand:(NSDictionary *)styles key:(NSString *)key render:(WeexCore::RenderObject*)render reserveStyles:(bool)reserveStyles |
| { |
| id data = styles[key]; |
| if (data) { |
| ConvertToCString(data, ^(const char * value) { |
| if (value != nullptr) { |
| render->AddStyle([key UTF8String], value, reserveStyles); |
| } |
| }); |
| } |
| } |
| |
| + (WeexCore::RenderObject*)_parseRenderObject:(NSDictionary *)data parent:(WeexCore::RenderObject *)parent index:(int)index pageId:(const std::string&)pageId reserveStyles:(bool)reserveStyles |
| { |
| using namespace WeexCore; |
| |
| const char* type = [data[@"type"] UTF8String]; |
| const char* ref = [data[@"ref"] UTF8String]; |
| if (type != nullptr && ref != nullptr) { |
| RenderObject* render = (RenderObject *)RenderCreator::GetInstance()->CreateRender(type, ref); |
| render->set_page_id(pageId); |
| if (parent != nullptr){ |
| parent->AddRenderObject(index, render); |
| } |
| |
| [data[@"attr"] enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) { |
| ConvertToCString(obj, ^(const char * value) { |
| if (value != nullptr) { |
| render->AddAttr([key UTF8String], value); |
| } |
| }); |
| }]; |
| |
| // margin/padding/borderWidth should be handled beforehand. Because maringLeft should override margin. |
| NSDictionary* styles = data[@"style"]; |
| [self _parseStyleBeforehand:styles key:@"margin" render:render reserveStyles:reserveStyles]; |
| [self _parseStyleBeforehand:styles key:@"padding" render:render reserveStyles:reserveStyles]; |
| [self _parseStyleBeforehand:styles key:@"borderWidth" render:render reserveStyles:reserveStyles]; |
| [styles enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) { |
| if ([key isEqualToString:@"margin"] || [key isEqualToString:@"padding"] || [key isEqualToString:@"borderWidth"]) { |
| return; |
| } |
| ConvertToCString(obj, ^(const char * value) { |
| if (value != nullptr) { |
| render->AddStyle([key UTF8String], value, reserveStyles); |
| } |
| }); |
| }]; |
| |
| for (id obj in data[@"event"]) { |
| ConvertToCString(obj, ^(const char * value) { |
| if (value != nullptr) { |
| render->AddEvent(value); |
| } |
| }); |
| } |
| |
| int childIndex = 0; |
| for (NSDictionary* obj in data[@"children"]) { |
| [self _parseRenderObject:obj parent:render index:childIndex ++ pageId:pageId reserveStyles:reserveStyles]; |
| } |
| |
| render->ApplyDefaultStyle(reserveStyles); |
| render->ApplyDefaultAttr(); |
| |
| return render; |
| } |
| return nullptr; |
| } |
| |
| + (std::vector<std::pair<std::string, std::string>>*)_parseMapValuePairs:(NSDictionary *)data |
| { |
| std::vector<std::pair<std::string, std::string>>* result = new std::vector<std::pair<std::string, std::string>>(); |
| [data enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) { |
| ConvertToCString(obj, ^(const char * value) { |
| if (value != nullptr) { |
| result->emplace_back([key UTF8String], value); |
| } |
| }); |
| }]; |
| return result; |
| } |
| |
| + (void)callAddElement:(NSString*)pageId parentRef:(NSString*)parentRef data:(NSDictionary*)data index:(int)index |
| { |
| using namespace WeexCore; |
| |
| const std::string page([pageId UTF8String] ?: ""); |
| RenderManager::GetInstance()->AddRenderObject(page, [parentRef UTF8String] ?: "", index, [&] (RenderPage* pageInstance) -> RenderObject* { |
| return [self _parseRenderObject:data parent:nullptr index:0 pageId:page reserveStyles:pageInstance->reserve_css_styles()]; |
| }); |
| } |
| |
| + (void)callCreateBody:(NSString*)pageId data:(NSDictionary*)data |
| { |
| using namespace WeexCore; |
| |
| WXSDKInstance* sdkInstance = [WXSDKManager instanceForID:pageId]; |
| WXComponentManager* manager = sdkInstance.componentManager; |
| if (!manager.isValid) { |
| return; |
| } |
| |
| SetConvertCurrentPage(pageId); |
| const std::string page([pageId UTF8String] ?: ""); |
| RenderManager::GetInstance()->CreatePage(page, [&] (RenderPage* pageInstance) -> RenderObject* { |
| pageInstance->set_before_layout_needed(false); // we do not need before and after layout |
| pageInstance->set_after_layout_needed(false); |
| pageInstance->set_platform_layout_needed(true); |
| return [self _parseRenderObject:data parent:nullptr index:0 pageId:page reserveStyles:pageInstance->reserve_css_styles()]; |
| }); |
| } |
| |
| + (void)callRemoveElement:(NSString*)pageId ref:(NSString*)ref |
| { |
| WeexCore::WeexCoreManager::Instance()->script_bridge()->core_side()->RemoveElement([pageId UTF8String] ?: "", [ref UTF8String] ?: ""); |
| } |
| |
| + (void)callMoveElement:(NSString*)pageId ref:(NSString*)ref parentRef:(NSString*)parentRef index:(int)index |
| { |
| WeexCore::WeexCoreManager::Instance()->script_bridge()->core_side()->MoveElement([pageId UTF8String] ?: "", [ref UTF8String] ?: "", [parentRef UTF8String] ?: "", index); |
| } |
| |
| + (void)callUpdateAttrs:(NSString*)pageId ref:(NSString*)ref data:(NSDictionary*)data |
| { |
| SetConvertCurrentPage(pageId); |
| WeexCore::RenderManager::GetInstance()->UpdateAttr([pageId UTF8String] ?: "", [ref UTF8String] ?: "", [self _parseMapValuePairs:data]); |
| } |
| |
| + (void)callUpdateStyle:(NSString*)pageId ref:(NSString*)ref data:(NSDictionary*)data |
| { |
| SetConvertCurrentPage(pageId); |
| WeexCore::RenderManager::GetInstance()->UpdateStyle([pageId UTF8String] ?: "", [ref UTF8String] ?: "", [self _parseMapValuePairs:data]); |
| } |
| |
| + (void)callAddEvent:(NSString*)pageId ref:(NSString*)ref event:(NSString*)event |
| { |
| WeexCore::WeexCoreManager::Instance()->script_bridge()->core_side()->AddEvent([pageId UTF8String] ?: "", [ref UTF8String] ?: "", [event UTF8String] ?: ""); |
| } |
| |
| + (void)callRemoveEvent:(NSString*)pageId ref:(NSString*)ref event:(NSString*)event |
| { |
| WeexCore::WeexCoreManager::Instance()->script_bridge()->core_side()->RemoveEvent([pageId UTF8String] ?: "", [ref UTF8String] ?: "", [event UTF8String] ?: ""); |
| } |
| |
| + (void)callCreateFinish:(NSString*)pageId |
| { |
| WeexCore::WeexCoreManager::Instance()->script_bridge()->core_side()->CreateFinish([pageId UTF8String] ?: ""); |
| } |
| |
| + (void)callRefreshFinish:(NSString*)pageId |
| { |
| WeexCore::WeexCoreManager::Instance()->script_bridge()->core_side()->RefreshFinish([pageId UTF8String] ?: "", nullptr, nullptr); |
| } |
| |
| + (void)callUpdateFinish:(NSString*)pageId |
| { |
| WeexCore::WeexCoreManager::Instance()->script_bridge()->core_side()->UpdateFinish([pageId UTF8String] ?: "", nullptr, 0, nullptr, 0); |
| } |
| |
| + (void)registerCoreEnv:(NSString*)key withValue:(NSString*)value |
| { |
| WeexCore::WeexCoreManager::Instance()->getPlatformBridge()->core_side()->RegisterCoreEnv([key UTF8String]?:"", [value UTF8String]?:""); |
| } |
| |
| + (void)setPageArgument:(NSString*)pageId key:(NSString*)key value:(NSString*)value |
| { |
| WeexCore::RenderManager::GetInstance()->setPageArgument([pageId UTF8String]?:"", [key UTF8String]?:"", [value UTF8String]?:""); |
| } |
| |
| + (BOOL)isKeepingRawCssStyles:(NSString*)pageId |
| { |
| RenderPageBase* page = RenderManager::GetInstance()->GetPage([pageId UTF8String] ?: ""); |
| if (page == nullptr) { |
| return NO; |
| } |
| return static_cast<RenderPage*>(page)->reserve_css_styles(); |
| } |
| |
| @end |