Skip to content

Commit

Permalink
test(ios): add test for event dispatcher and code clean
Browse files Browse the repository at this point in the history
  • Loading branch information
wwwcg committed Nov 27, 2024
1 parent 17b5c35 commit d73e6f1
Show file tree
Hide file tree
Showing 7 changed files with 179 additions and 107 deletions.
16 changes: 8 additions & 8 deletions docs/development/native-event.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,14 +132,14 @@ hippyEngine.sendEvent("rotate", hippyMap);
终端在需要发送事件的地方调用代码:

```objectivec
// 也可以参考HippyEventObserverModule.m
[self sendEvent: @"rotate" params: @{@"foo":@"bar"}];
- (void)sendEvent:(NSString *)eventName params:(NSDictionary *)params
{
HippyAssertParam(eventName);
// 这里的"EventDispatcher"和"receiveNativeEvent"是常量,无需也不能更改
[self.bridge.eventDispatcher dispatchEvent:@"EventDispatcher" methodName:@"receiveNativeEvent" args:@{@"eventName": eventName, @"extra": params ? : @{}}];
}
// 调用HippyBridge的如下实例方法,比如:
[self.hippyBridge sendEvent:@"rotate" params:@{@"foo":@"bar"}];

/// Send native event to JS side
/// - Parameters:
/// - eventName: event name
/// - params: event info
- (void)sendEvent:(NSString *)eventName params:(NSDictionary *_Nullable)params;
```
# Voltron
Expand Down
2 changes: 1 addition & 1 deletion framework/ios/base/bridge/HippyBridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ HIPPY_EXTERN NSString *HippyBridgeModuleNameForClass(Class bridgeModuleClass);
- (void)requestReload;


#pragma mark -
#pragma mark - JS Communication Related

/// Access the underlying JavaScript executor.
/// You can use this in unit tests to detect when the executor has been invalidated,
Expand Down
85 changes: 43 additions & 42 deletions framework/ios/base/bridge/HippyBridge.mm
Original file line number Diff line number Diff line change
Expand Up @@ -96,15 +96,23 @@
NSString *const kHippyLaunchOptionsDebugModeKey = @"DebugMode";
NSString *const kHippyLaunchOptionsEnableTurboKey = @"EnableTurbo";

// Global device info keys
static NSString *const HippyNativeGlobalKeyOS = @"OS";
static NSString *const HippyNativeGlobalKeyOSVersion = @"OSVersion";
static NSString *const HippyNativeGlobalKeyDevice = @"Device";
static NSString *const HippyNativeGlobalKeySDKVersion = @"SDKVersion";
static NSString *const HippyNativeGlobalKeyAppVersion = @"AppVersion";
static NSString *const HippyNativeGlobalKeyDimensions = @"Dimensions";
static NSString *const HippyNativeGlobalKeyLocalization = @"Localization";
static NSString *const HippyNativeGlobalKeyNightMode = @"NightMode";
// Global device info keys & values
static NSString *const kHippyNativeGlobalKeyOS = @"OS";
static NSString *const kHippyNativeGlobalKeyOSVersion = @"OSVersion";
static NSString *const kHippyNativeGlobalKeyDevice = @"Device";
static NSString *const kHippyNativeGlobalKeySDKVersion = @"SDKVersion";
static NSString *const kHippyNativeGlobalKeyAppVersion = @"AppVersion";
static NSString *const kHippyNativeGlobalKeyDimensions = @"Dimensions";
static NSString *const kHippyNativeGlobalKeyLocalization = @"Localization";
static NSString *const kHippyNativeGlobalKeyNightMode = @"NightMode";
static NSString *const kHippyNativeGlobalOSValue = @"ios";
static NSString *const kHippyCFBundleShortVersionKey = @"CFBundleShortVersionString";

// Localization infos
static NSString *const kHippyLocalizaitionCountryKey = @"country";
static NSString *const kHippyLocalizaitionLanguageKey = @"language";
static NSString *const kHippyLocalizaitionDirectionKey = @"direction";
static NSString *const kHippyLocalizaitionValueUnknown = @"unknown";

// Key of module config info for js side
static NSString *const kHippyRemoteModuleConfigKey = @"remoteModuleConfig";
Expand Down Expand Up @@ -657,7 +665,8 @@ - (id)callNativeModule:(NSUInteger)moduleID method:(NSUInteger)methodID params:(
NSArray<HippyModuleData *> *moduleDataByID = [_moduleSetup moduleDataByID];
if (moduleID >= [moduleDataByID count]) {
if (isValid) {
HippyLogError(@"moduleID %lu exceed range of moduleDataByID %lu, bridge is valid %ld", moduleID, [moduleDataByID count], (long)isValid);
HippyLogError(@"moduleID %lu exceed range of moduleDataByID %lu, bridge is valid %ld",
moduleID, [moduleDataByID count], (long)isValid);
}
return nil;
}
Expand All @@ -668,23 +677,19 @@ - (id)callNativeModule:(NSUInteger)moduleID method:(NSUInteger)methodID params:(
}
return nil;
}
// not for UI Actions if NO==_valid
if (!isValid) {
if ([[moduleData name] isEqualToString:@"UIManager"]) {
return nil;
}
}
NSArray<id<HippyBridgeMethod>> *methods = [moduleData.methods copy];
if (methodID >= [methods count]) {
if (isValid) {
HippyLogError(@"methodID %lu exceed range of moduleData.methods %lu, bridge is valid %ld", moduleID, [methods count], (long)isValid);
HippyLogError(@"methodID %lu exceed range of moduleData.methods %lu, bridge is valid %ld",
moduleID, [methods count], (long)isValid);
}
return nil;
}
id<HippyBridgeMethod> method = methods[methodID];
if (HIPPY_DEBUG && !method) {
if (isValid) {
HippyLogError(@"Unknown methodID: %lu for module: %lu (%@)", (unsigned long)methodID, (unsigned long)moduleID, moduleData.name);
HippyLogError(@"Unknown methodID: %lu for module: %lu (%@)",
(unsigned long)methodID, (unsigned long)moduleID, moduleData.name);
}
return nil;
}
Expand Down Expand Up @@ -713,7 +718,8 @@ - (id)callNativeModule:(NSUInteger)moduleID method:(NSUInteger)methodID params:(
@throw exception;
}

NSString *message = [NSString stringWithFormat:@"Exception '%@' was thrown while invoking %@ on target %@ with params %@", exception, method.JSMethodName, moduleData.name, params];
NSString *message = [NSString stringWithFormat:@"Exception '%@' was thrown while invoking %@ on target %@ with params %@",
exception, method.JSMethodName, moduleData.name, params];
NSError *error = HippyErrorWithMessage(message);
HippyBridgeFatal(error, self);
return nil;
Expand All @@ -737,7 +743,8 @@ - (id)callNativeModuleName:(NSString *)moduleName methodName:(NSString *)methodN
@throw exception;
}

NSString *message = [NSString stringWithFormat:@"Exception '%@' was thrown while invoking %@ on target %@ with params %@", exception, method.JSMethodName, module.name, params];
NSString *message = [NSString stringWithFormat:@"Exception '%@' was thrown while invoking %@ on target %@ with params %@",
exception, method.JSMethodName, module.name, params];
HippyBridgeFatal(HippyErrorWithMessage(message), self);
return nil;
}
Expand Down Expand Up @@ -842,30 +849,29 @@ - (NSDictionary *)genRawDeviceInfoDict {
uname(&systemInfo);
NSString *deviceModel = [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding];
NSMutableDictionary *deviceInfo = [NSMutableDictionary dictionary];
[deviceInfo setValue:@"ios" forKey:HippyNativeGlobalKeyOS];
[deviceInfo setValue:iosVersion forKey:HippyNativeGlobalKeyOSVersion];
[deviceInfo setValue:deviceModel forKey:HippyNativeGlobalKeyDevice];
[deviceInfo setValue:_HippySDKVersion forKey:HippyNativeGlobalKeySDKVersion];

NSString *appVer = [[NSBundle.mainBundle infoDictionary] objectForKey:@"CFBundleShortVersionString"];
deviceInfo[kHippyNativeGlobalKeyOS] = kHippyNativeGlobalOSValue;
deviceInfo[kHippyNativeGlobalKeyOSVersion] = iosVersion;
deviceInfo[kHippyNativeGlobalKeyDevice] = deviceModel;
deviceInfo[kHippyNativeGlobalKeySDKVersion] = _HippySDKVersion;
NSString *appVer = [[NSBundle.mainBundle infoDictionary] objectForKey:kHippyCFBundleShortVersionKey];
if (appVer) {
[deviceInfo setValue:appVer forKey:HippyNativeGlobalKeyAppVersion];
deviceInfo[kHippyNativeGlobalKeyAppVersion] = appVer;
}

if (self.cachedDimensionsInfo) {
[deviceInfo setValue:self.cachedDimensionsInfo forKey:HippyNativeGlobalKeyDimensions];
deviceInfo[kHippyNativeGlobalKeyDimensions] = self.cachedDimensionsInfo;
}

NSString *countryCode = [[HippyI18nUtils sharedInstance] currentCountryCode];
NSString *lanCode = [[HippyI18nUtils sharedInstance] currentAppLanguageCode];
NSWritingDirection direction = [[HippyI18nUtils sharedInstance] writingDirectionForCurrentAppLanguage];
NSDictionary *localizaitionInfo = @{
@"country" : countryCode?:@"unknown",
@"language" : lanCode?:@"unknown",
@"direction" : @(direction)
kHippyLocalizaitionCountryKey : countryCode ?: kHippyLocalizaitionValueUnknown,
kHippyLocalizaitionLanguageKey : lanCode ?: kHippyLocalizaitionValueUnknown,
kHippyLocalizaitionDirectionKey : @(direction)
};
[deviceInfo setValue:localizaitionInfo forKey:HippyNativeGlobalKeyLocalization];
[deviceInfo setValue:@([self isOSNightMode]) forKey:HippyNativeGlobalKeyNightMode];
deviceInfo[kHippyNativeGlobalKeyLocalization] = localizaitionInfo;
deviceInfo[kHippyNativeGlobalKeyNightMode] = @([self isOSNightMode]);
return deviceInfo;
}

Expand All @@ -889,14 +895,11 @@ - (void)setOSNightMode:(BOOL)isOSNightMode withRootViewTag:(nonnull NSNumber *)r
_isOSNightMode = isOSNightMode;
// Notify to JS Driver Side
// 1. Update global object
[self.javaScriptExecutor updateNativeInfoToHippyGlobalObject:@{ HippyNativeGlobalKeyNightMode: @(isOSNightMode) }];
[self.javaScriptExecutor updateNativeInfoToHippyGlobalObject:@{ kHippyNativeGlobalKeyNightMode: @(isOSNightMode) }];

// 2. Send event
NSDictionary *args = @{@"eventName": hippyOnNightModeChangedEvent,
@"extra": @{ hippyOnNightModeChangedParam1 : @(isOSNightMode),
hippyOnNightModeChangedParam2 : rootViewTag } };
[self.eventDispatcher dispatchEvent:@"EventDispatcher"
methodName:@"receiveNativeEvent" args:args];
[self sendEvent:hippyOnNightModeChangedEvent params:@{ hippyOnNightModeChangedParam1 : @(isOSNightMode),
hippyOnNightModeChangedParam2 : rootViewTag }];
}


Expand Down Expand Up @@ -946,9 +949,7 @@ - (void)setContextName:(NSString *)contextName {
}

- (void)sendEvent:(NSString *)eventName params:(NSDictionary *_Nullable)params {
[self.eventDispatcher dispatchEvent:@"EventDispatcher"
methodName:@"receiveNativeEvent"
args:@{@"eventName": eventName, @"extra": params ? : @{}}];
[self.eventDispatcher dispatchNativeEvent:eventName withParams:params];
}


Expand Down
24 changes: 11 additions & 13 deletions framework/ios/base/modules/HippyEventDispatcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,34 +21,32 @@
*/

#import <UIKit/UIKit.h>

#import "HippyBridge.h"

/**
* The threshold at which text inputs will start warning that the JS thread
* has fallen behind (resulting in poor input performance, missed keys, etc.)
*/
HIPPY_EXTERN const NSInteger HippyTextUpdateLagWarningThreshold;

/**
* Takes an input event name and normalizes it to the form that is required
* by the events system (currently that means starting with the "top" prefix,
* but that's an implementation detail that may change in future).
*/
HIPPY_EXTERN NSString *HippyNormalizeInputEventName(NSString *eventName);
NS_ASSUME_NONNULL_BEGIN

/**
* This class wraps the -[HippyBridge enqueueJSCall:args:] method, and
* provides some convenience methods for generating event calls.
*/
@interface HippyEventDispatcher : NSObject <HippyBridgeModule>

/// Send event to JS side with given params.
- (void)dispatchEvent:(NSString *)moduleName methodName:(NSString *)methodName args:(NSDictionary *)params;

/// Similar to the above `dispatchEvent` method, but designed to send Native events only.
/// - Parameters:
/// - eventName: name of event
/// - params: event params
- (void)dispatchNativeEvent:(NSString *)eventName withParams:(nullable NSDictionary *)params;

@end

@interface HippyBridge (HippyEventDispatcher)

/// A dispatcher responsible for sending event to js side.
- (HippyEventDispatcher *)eventDispatcher;

@end

NS_ASSUME_NONNULL_END
71 changes: 44 additions & 27 deletions framework/ios/base/modules/HippyEventDispatcher.mm
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,19 @@
#import "HippyUtils.h"
#import "HippyBridge+ModuleManage.h"

const NSInteger HippyTextUpdateLagWarningThreshold = 3;

NSString *HippyNormalizeInputEventName(NSString *eventName) {
if ([eventName hasPrefix:@"on"]) {
eventName = [eventName stringByReplacingCharactersInRange:(NSRange) { 0, 2 } withString:@"top"];
} else if (![eventName hasPrefix:@"top"]) {
eventName = [[@"top" stringByAppendingString:[eventName substringToIndex:1].uppercaseString]
stringByAppendingString:[eventName substringFromIndex:1]];
}
return eventName;
}
static NSString *const kHippyCallJSModuleKey = @"callJsModule";
static NSString *const kHippyEventDispatcherModuleNameKey = @"moduleName";
static NSString *const kHippyEventDispatcherMethodNameKey = @"methodName";
static NSString *const kHippyEventDispatcherParamsKey = @"params";

static NSString *const kHippyEventDispatcherModule = @"EventDispatcher";
static NSString *const kHippyReceiveNativeEventMethod = @"receiveNativeEvent";
static NSString *const kHippyReceiveUIEventMethod = @"receiveUIComponentEvent";
static NSString *const kHippyReceiveGestureEventMethod = @"receiveNativeGesture";
static NSString *const kHippyEventNameKey = @"eventName";
static NSString *const kHippyEventParamsKey = @"extra";
static NSString *const kHippyEventIdKey = @"id";


@implementation HippyEventDispatcher

Expand All @@ -44,43 +46,58 @@ @implementation HippyEventDispatcher
HIPPY_EXPORT_MODULE()

- (void)dispatchEvent:(NSString *)moduleName methodName:(NSString *)methodName args:(NSDictionary *)params {
NSString *action = @"callJsModule";
NSMutableArray *events = [NSMutableArray array];
[events addObject:action];
[events addObject:kHippyCallJSModuleKey];

NSMutableDictionary *body = [NSMutableDictionary new];
[body setObject:moduleName forKey:@"moduleName"];
[body setObject:methodName forKey:@"methodName"];

if ([moduleName isEqualToString:@"EventDispatcher"] && params) {
NSNumber *tag = params[@"id"];
NSString *eventName = params[@"eventName"] ?: @"";
NSDictionary *extra = params[@"extra"] ?: @{};
if ([methodName isEqualToString:@"receiveNativeEvent"]) {
[body setObject:moduleName forKey:kHippyEventDispatcherModuleNameKey];
[body setObject:methodName forKey:kHippyEventDispatcherMethodNameKey];

if ([moduleName isEqualToString:kHippyEventDispatcherModule] && params) {
NSString *eventName = params[kHippyEventNameKey] ?: @"";
NSDictionary *extra = params[kHippyEventParamsKey] ?: @{};
if ([methodName isEqualToString:kHippyReceiveNativeEventMethod]) {
NSMutableArray *detail = [NSMutableArray new];
[detail addObject:eventName];
[detail addObject:extra];
[body setValue:detail forKey:@"params"];
} else if ([methodName isEqualToString:@"receiveUIComponentEvent"]) {
[body setValue:detail forKey:kHippyEventDispatcherParamsKey];
} else if ([methodName isEqualToString:kHippyReceiveUIEventMethod]) {
NSNumber *tag = params[kHippyEventIdKey];
NSMutableArray *detail = [NSMutableArray new];
if (tag) {
[detail addObject:tag];
}
[detail addObject:eventName];
[detail addObject:extra];
[body setValue:detail forKey:@"params"];
} else if ([methodName isEqualToString:@"receiveNativeGesture"]) {
[body setValue:params forKey:@"params"];
[body setValue:detail forKey:kHippyEventDispatcherParamsKey];
} else if ([methodName isEqualToString:kHippyReceiveGestureEventMethod]) {
[body setValue:params forKey:kHippyEventDispatcherParamsKey];
}
} else {
[body setValue:params forKey:@"params"];
[body setValue:params forKey:kHippyEventDispatcherParamsKey];
}

[events addObject:body];

[_bridge enqueueJSCall:moduleName method:methodName args:events completion:NULL];
}

- (void)dispatchNativeEvent:(NSString *)eventName withParams:(NSDictionary *)params {
NSMutableDictionary *body = [NSMutableDictionary new];
body[kHippyEventDispatcherModuleNameKey] = kHippyEventDispatcherModule;
body[kHippyEventDispatcherMethodNameKey] = kHippyReceiveNativeEventMethod;
body[kHippyEventDispatcherParamsKey] = @[ (eventName ?: @""), (params ?: @{}) ];

NSMutableArray *events = [NSMutableArray array];
[events addObject:kHippyCallJSModuleKey];
[events addObject:body];

[_bridge enqueueJSCall:kHippyEventDispatcherModule
method:kHippyReceiveNativeEventMethod
args:events
completion:nil];
}

- (dispatch_queue_t)methodQueue {
return HippyJSThread;
}
Expand Down
22 changes: 6 additions & 16 deletions framework/ios/module/eventobserver/HippyEventObserverModule.mm
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,11 @@ @implementation HippyEventObserverModule {

HIPPY_EXPORT_MODULE(EventObserver)

- (dispatch_queue_t)methodQueue
{
- (dispatch_queue_t)methodQueue {
return dispatch_get_main_queue();
}

- (instancetype)init
{
- (instancetype)init {
if (self = [super init]) {
_config = [NSMutableDictionary new];
}
Expand Down Expand Up @@ -68,26 +66,18 @@ - (instancetype)init
}
}

- (void)addEventObserverForName:(__unused NSString *)eventName
{
- (void)addEventObserverForName:(__unused NSString *)eventName {
// should override by subclass
// do sth
}

- (void)removeEventObserverForName:(__unused NSString *)eventName
{
- (void)removeEventObserverForName:(__unused NSString *)eventName {
// should override by subclass
// do sth
}

- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver: self];
}

- (void)sendEvent:(NSString *)eventName params:(NSDictionary *)params
{
- (void)sendEvent:(NSString *)eventName params:(NSDictionary *)params {
HippyAssertParam(eventName);
[self.bridge.eventDispatcher dispatchEvent:@"EventDispatcher" methodName:@"receiveNativeEvent" args:@{@"eventName": eventName, @"extra": params ? : @{}}];
[self.bridge.eventDispatcher dispatchNativeEvent:eventName withParams:params];
}
@end
Loading

0 comments on commit d73e6f1

Please sign in to comment.