Skip to content

Commit

Permalink
feat(ios): add NightMode and host GlobalEnvInfo
Browse files Browse the repository at this point in the history
  • Loading branch information
wwwcg committed Jul 25, 2023
1 parent 1d33a07 commit a6b1877
Show file tree
Hide file tree
Showing 14 changed files with 425 additions and 221 deletions.
34 changes: 26 additions & 8 deletions examples/ios-demo/HippyDemo/TestModule.m
Original file line number Diff line number Diff line change
Expand Up @@ -41,30 +41,26 @@ - (dispatch_queue_t)methodQueue

HIPPY_EXPORT_METHOD(debug:(nonnull NSNumber *)instanceId)
{
//#define REMOTEDEBUG

#ifdef REMOTEDEBUG
AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
UIViewController *nav = delegate.window.rootViewController;
UIViewController *vc = [[UIViewController alloc] init];
BOOL isSimulator = NO;
#if TARGET_IPHONE_SIMULATOR
isSimulator = YES;
#endif


//#define REMOTEDEBUG

#ifdef REMOTEDEBUG
NSURL *url = [NSURL URLWithString:@"your server ip address"];
HippyBridge *bridge = [[HippyBridge alloc] initWithBundleURL:url moduleProvider:nil launchOptions:nil];
HippyRootView *rootView = [[HippyRootView alloc] initWithBridge:bridge moduleName:@"your module name" initialProperties:@{@"isSimulator": @(isSimulator) shareOptions:nil delegate:nil];
#else
HippyRootView *rootView = [[HippyRootView alloc] initWithBridge:nil businessURL:nil moduleName:@"Demo" initialProperties:@{@"isSimulator": @(isSimulator)} launchOptions:nil shareOptions:nil debugMode:YES delegate:nil];
rootView.bridge.enableTurbo = YES; // keep the same logic with Android
#endif
rootView.backgroundColor = [UIColor whiteColor];
rootView.frame = vc.view.bounds;
[vc.view addSubview:rootView];
vc.modalPresentationStyle = UIModalPresentationFullScreen;
[nav presentViewController:vc animated:YES completion:NULL];
#endif
}

HIPPY_EXPORT_METHOD(remoteDebug:(nonnull NSNumber *)instanceId bundleUrl:(nonnull NSString *)bundleUrl)
Expand Down Expand Up @@ -100,4 +96,26 @@ - (NSURL *)inspectorSourceURLForBridge:(HippyBridge *)bridge {
return bridge.bundleURL;
}

#pragma mark - Delegate

- (HippyGlobalEnvInfoFromHost *)globalEnvInfoFromHost {
HippyGlobalEnvInfoFromHost *globalEnv = [[HippyGlobalEnvInfoFromHost alloc] init];
// 1. App版本号,选填
globalEnv.appVerson = [[NSBundle.mainBundle infoDictionary] objectForKey:@"CFBundleShortVersionString"];

// 2. 默认状态栏高度
// 说明:状态栏高度通常为动态获取,且不可作为页面布局时的依赖,然而部分页面初始化时依赖状态栏高度进行布局,
// 为兼容部分旧代码布局,特提供此设置接口,作为默认的兜底值。
// 如无需兼容,可不设置或置0
globalEnv.defaultStatusBarHeight = 0; //[self getDefaultStatusBarHeight];

// 3. 是否使用viewWillTransitionToSize方法替换UIApplicationDidChangeStatusBarOrientationNotification通知,
// 推荐设置 (该系统通知已废弃,且部分场景下存在异常)
// 注意,设置后必须实现viewWillTransitionToSize方法,并调用onHostControllerTransitionedToSize向hippy同步事件。
globalEnv.useViewWillTransitionMethodToMonitorOrientation = NO;

return globalEnv;
}


@end
114 changes: 84 additions & 30 deletions examples/ios-demo/HippyDemo/ViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,24 @@
#import "HippyLog.h"
#import "HippyBundleURLProvider.h"
#import "DemoConfigs.h"
#import <sys/utsname.h>

@interface ViewController ()<HippyBridgeDelegate, HippyMethodInterceptorProtocol>

//release macro below if use debug mode
//#define HIPPYDEBUG


@interface ViewController () <HippyBridgeDelegate, HippyMethodInterceptorProtocol>

/// Hippy Root View
@property (nonatomic, strong) HippyRootView *hippyRootView;

@end

@implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.

HippySetLogFunction(^(HippyLogLevel level, HippyLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) {
NSLog(@"hippy says:%@ in file [%@:%d]", message, fileName, lineNumber.intValue);
Expand All @@ -46,10 +54,7 @@ - (void)viewDidLoad {
isSimulator = YES;
#endif


//release macro below if use debug mode
//#define HIPPYDEBUG


#ifdef HIPPYDEBUG
NSDictionary *launchOptions = @{@"EnableTurbo": @(DEMO_ENABLE_TURBO), @"DebugMode": @(YES)};
NSString *bundleStr = [HippyBundleURLProvider sharedInstance].bundleURLString;
Expand All @@ -59,8 +64,13 @@ - (void)viewDidLoad {
moduleProvider:nil
launchOptions:launchOptions
executorKey:@"Demo"];
HippyRootView *rootView = [[HippyRootView alloc] initWithBridge:bridge moduleName:@"Demo" initialProperties:@{@"isSimulator": @(isSimulator)} shareOptions:@{@"DebugMode": @(YES)} delegate:nil];
HippyRootView *rootView = [[HippyRootView alloc] initWithBridge:bridge
moduleName:@"Demo"
initialProperties:@{@"isSimulator": @(isSimulator)}
shareOptions:@{@"DebugMode": @(YES)}
delegate:nil];
#else

NSString *commonBundlePath = [[NSBundle mainBundle] pathForResource:@"vendor.ios" ofType:@"js" inDirectory:@"res"];
NSString *businessBundlePath = [[NSBundle mainBundle] pathForResource:@"index.ios" ofType:@"js" inDirectory:@"res"];
NSDictionary *launchOptions = @{@"EnableTurbo": @(DEMO_ENABLE_TURBO)};
Expand All @@ -69,26 +79,48 @@ - (void)viewDidLoad {
moduleProvider:nil
launchOptions:launchOptions
executorKey:@"Demo"];
HippyRootView *rootView = [[HippyRootView alloc] initWithBridge:bridge businessURL:[NSURL fileURLWithPath:businessBundlePath] moduleName:@"Demo" initialProperties: @{@"isSimulator": @(isSimulator)} launchOptions:nil shareOptions:nil debugMode:NO delegate:nil];
HippyRootView *rootView = [[HippyRootView alloc] initWithBridge:bridge
businessURL:[NSURL fileURLWithPath:businessBundlePath]
moduleName:@"Demo"
initialProperties:@{@"isSimulator": @(isSimulator)}
launchOptions:nil
shareOptions:nil
delegate:nil];
#endif
bridge.methodInterceptor = self;


// HippyBridge *bridge = [[HippyBridge alloc] initWithDelegate:self bundleURL:[NSURL URLWithString:@"http://localhost:38989/index.bundle?platform=ios&dev=true&minify=false"] moduleProvider:nil launchOptions:nil executorKey:@"Demo"];
// HippyRootView *rootView = [[HippyRootView alloc] initWithBridge:bridge moduleName:@"Demo" initialProperties:nil shareOptions:nil delegate:nil];;


rootView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
rootView.frame = self.view.bounds;
[self.view addSubview:rootView];
self.hippyRootView = rootView;
}


#pragma mark - HippyBridgeDelegate

/// 必要协议方法,提供Hippy宿主相关的必要信息
- (HippyGlobalEnvInfoFromHost *)globalEnvInfoFromHost {
HippyGlobalEnvInfoFromHost *globalEnv = [[HippyGlobalEnvInfoFromHost alloc] init];
// 1. App版本号,选填
globalEnv.appVerson = [[NSBundle.mainBundle infoDictionary] objectForKey:@"CFBundleShortVersionString"];

// 2. 默认状态栏高度
// 说明:状态栏高度通常为动态获取,且不可作为页面布局时的依赖,然而部分页面初始化时依赖状态栏高度进行布局,
// 为兼容部分旧代码布局,特提供此设置接口,作为默认的兜底值。
globalEnv.defaultStatusBarHeight = [self getDefaultStatusBarHeight];

// 3. 是否使用viewWillTransitionToSize方法替换UIApplicationDidChangeStatusBarOrientationNotification通知,
// 推荐设置 (该系统通知已废弃,且部分场景下存在异常)
// 注意,设置后必须实现viewWillTransitionToSize方法,并调用onHostControllerTransitionedToSize向hippy同步事件。
globalEnv.useViewWillTransitionMethodToMonitorOrientation = YES;

return globalEnv;
}

- (NSDictionary *)objectsBeforeExecuteCode {
NSDictionary *dic1 = @{@"name": @"zs", @"gender": @"male"};
NSDictionary *dic2 = @{@"name": @"ls", @"gender": @"male"};
NSDictionary *dic3 = @{@"name": @"ww", @"gender": @"female"};

NSDictionary *ret = @{@"info1": dic1, @"info2": dic2, @"info3": dic3};
return ret;
}
Expand All @@ -102,20 +134,9 @@ - (NSDictionary *)objectsBeforeExecuteSecondaryCode {
}

- (BOOL)dynamicLoad:(HippyBridge *)bridge URI:(NSString *)uri completion:(void (^)(NSString *))completion {
// NSURL *url = [NSURL URLWithString:uri];
// NSURLRequest *req = [NSURLRequest requestWithURL:url];
// [[NSURLSession sharedSession] dataTaskWithRequest:req completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
// if (error) {
// NSLog(@"dynamic load error: %@", [error description]);
// }
// else {
// NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
// completion(result);
// }
// }];;
//简单处理,直接返回。
// completion(@"var a = 1");
return false;
// Demo,直接返回。
completion(@"var a = 1");
return YES;
}

- (BOOL)shouldStartInspector:(HippyBridge *)bridge {
Expand All @@ -126,16 +147,49 @@ - (NSURL *)inspectorSourceURLForBridge:(HippyBridge *)bridge {
return bridge.bundleURL;
}

- (BOOL)shouldInvokeWithModuleName:(NSString *)moduleName methodName:(NSString *)methodName arguments:(NSArray<id<HippyBridgeArgument>> *)arguments argumentsValues:(NSArray *)argumentsValue containCallback:(BOOL)containCallback {

#pragma mark - HippyMethodInterceptorProtocol

- (BOOL)shouldInvokeWithModuleName:(NSString *)moduleName
methodName:(NSString *)methodName
arguments:(NSArray<id<HippyBridgeArgument>> *)arguments
argumentsValues:(NSArray *)argumentsValue
containCallback:(BOOL)containCallback {
HippyAssert(moduleName, @"module name must not be null");
HippyAssert(methodName, @"method name must not be null");
return YES;
}

- (BOOL)shouldCallbackBeInvokedWithModuleName:(NSString *)moduleName methodName:(NSString *)methodName callbackId:(NSNumber *)cbId arguments:(id)arguments {
- (BOOL)shouldCallbackBeInvokedWithModuleName:(NSString *)moduleName
methodName:(NSString *)methodName
callbackId:(NSNumber *)cbId
arguments:(id)arguments {
HippyAssert(moduleName, @"module name must not be null");
HippyAssert(methodName, @"method name must not be null");
return YES;
}


#pragma mark - View Controller Size Change

- (void)viewWillTransitionToSize:(CGSize)size
withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
[coordinator animateAlongsideTransition:nil completion:^(id<UIViewControllerTransitionCoordinatorContext> context) {
// Note that `useViewWillTransitionMethodToMonitorOrientation` flag must be set when init bridge,
// otherwise calling this function takes no effect.
[self.hippyRootView onHostControllerTransitionedToSize:size];
}];
}


#pragma mark - Helper Methods

- (CGFloat)getDefaultStatusBarHeight {
// Hippy旧版本SDK内部的默认实现,由于不同设备状态栏高度不同,该方法存在缺陷
// 注意:生产代码请根据机型自行判断并提供默认值
BOOL isAboveIPhoneX = ([[UIApplication sharedApplication] delegate].window.safeAreaInsets.bottom > 0.0);
return isAboveIPhoneX ? 44 : 20;
}

@end
83 changes: 55 additions & 28 deletions ios/sdk/base/HippyBatchedBridge.mm
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
*/

#import <Foundation/Foundation.h>

#import "HippyAssert.h"
#import "HippyBridge.h"
#import "HippyBridge+Private.h"
Expand All @@ -41,21 +40,22 @@
#import "HippyDevManager.h"
#import "HippyBundleURLProvider.h"
#import "HippyTurboModuleManager.h"

#import "HippyDeviceBaseInfo.h"
#import <sys/utsname.h>
#include "core/scope.h"

#define HippyAssertJSThread()
//
// #define HippyAssertJSThread() \
//HippyAssert(![NSStringFromClass([self->_javaScriptExecutor class]) isEqualToString:@"HippyJSCExecutor"] || \
//[[[NSThread currentThread] name] isEqualToString:HippyJSCThreadName], \
//@"This method must be called on JS thread")
#import <sys/utsname.h>

#define HippyAssertJSThread() \
//HippyAssert(![NSStringFromClass([self->_javaScriptExecutor class]) isEqualToString:@"HippyJSCExecutor"] || \
//[[[NSThread currentThread] name] isEqualToString:HippyJSCThreadName], \
//@"This method must be called on JS thread")
#define HippyAssertJSThread() // TODO: add assert imp

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";
NSString *const HippyNativeGlobalKeyNightMode = @"NightMode";


/**
* Must be kept in sync with `MessageQueue.js`.
Expand All @@ -67,6 +67,16 @@ typedef NS_ENUM(NSUInteger, HippyBridgeFields) {
HippyBridgeFieldCallID,
};


#pragma mark -

@interface HippyBatchedBridge ()

/// A helper class for getting device related info, like `Dimensions`.
@property (nonatomic, strong) HippyDeviceBaseInfo *deviceBaseInfo;

@end

@implementation HippyBatchedBridge {
BOOL _wasBatchActive;
NSMutableArray<dispatch_block_t> *_pendingCalls;
Expand All @@ -91,13 +101,15 @@ @implementation HippyBatchedBridge {
- (instancetype)initWithParentBridge:(HippyBridge *)bridge {
HippyAssertParam(bridge);

if (self = [super initWithDelegate:bridge.delegate bundleURL:bridge.bundleURL moduleProvider:bridge.moduleProvider
if (self = [super initWithDelegate:bridge.delegate
bundleURL:bridge.bundleURL
moduleProvider:bridge.moduleProvider
launchOptions:bridge.launchOptions
executorKey:bridge.executorKey]) {
HippyExecuteOnMainThread(
^{
self->_dimDic = hippyExportedDimensions();
}, YES);
HippyExecuteOnMainThread(^{
self->_dimDic = hippyExportedDimensions(bridge);
[bridge setOSNightMode:isHippyScreenInOSDarkMode() notifyToJS:NO];
}, YES);
_parentBridge = bridge;
_performanceLogger = [bridge performanceLogger];
/**
Expand All @@ -107,6 +119,7 @@ - (instancetype)initWithParentBridge:(HippyBridge *)bridge {
_loading = YES;
_pendingCalls = [NSMutableArray new];
_displayLink = [HippyDisplayLink new];
_deviceBaseInfo = [[HippyDeviceBaseInfo alloc] initWithHippyBridge:bridge];

[HippyBridge setCurrentBridge:self];
HippyLogInfo(@"[Hippy_OC_Log][Life_Circle],HippyBatchedBridge Init %p", self);
Expand Down Expand Up @@ -587,26 +600,36 @@ - (void)executeSourceCode:(NSData *)sourceCode {
}

- (NSDictionary *)deviceInfo {
//该方法可能从非UI线程调用
NSString *iosVersion = [[UIDevice currentDevice] systemVersion];
struct utsname systemInfo;
uname(&systemInfo);
NSString *deviceModel = [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding];
NSMutableDictionary *deviceInfo = [NSMutableDictionary dictionary];
[deviceInfo setValue:@"ios" forKey:@"OS"];
[deviceInfo setValue:iosVersion forKey:@"OSVersion"];
[deviceInfo setValue:deviceModel forKey:@"Device"];
[deviceInfo setValue:_HippySDKVersion forKey:@"SDKVersion"];
[deviceInfo setValue:_parentBridge.appVerson forKey:@"AppVersion"];
[deviceInfo setValue:@"ios" forKey:HippyNativeGlobalKeyOS];
[deviceInfo setValue:iosVersion forKey:HippyNativeGlobalKeyOSVersion];
[deviceInfo setValue:deviceModel forKey:HippyNativeGlobalKeyDevice];
[deviceInfo setValue:_HippySDKVersion forKey:HippyNativeGlobalKeySDKVersion];

NSString *appVer = self.parentBridge.globalEnvInfo.appVerson;
if (appVer) {
[deviceInfo setValue:appVer forKey:HippyNativeGlobalKeyAppVersion];
}

if (_dimDic) {
[deviceInfo setValue:_dimDic forKey:@"Dimensions"];
[deviceInfo setValue:_dimDic forKey:HippyNativeGlobalKeyDimensions];
}

NSString *countryCode = [[HippyI18nUtils sharedInstance] currentCountryCode];
NSString *lanCode = [[HippyI18nUtils sharedInstance] currentAppLanguageCode];
NSWritingDirection direction = [[HippyI18nUtils sharedInstance] writingDirectionForCurrentAppLanguage];
NSDictionary *local = @{@"country": countryCode?:@"unknown", @"language": lanCode?:@"unknown", @"direction": @(direction)};
[deviceInfo setValue:local forKey:@"Localization"];
return [NSDictionary dictionaryWithDictionary:deviceInfo];
NSDictionary *localizaitionInfo = @{
@"country" : countryCode?:@"unknown",
@"language" : lanCode?:@"unknown",
@"direction" : @(direction)
};
[deviceInfo setValue:localizaitionInfo forKey:HippyNativeGlobalKeyLocalization];
[deviceInfo setValue:@([self.parentBridge isOSNightMode]) forKey:HippyNativeGlobalKeyNightMode];
return deviceInfo;
}

- (void)_flushPendingCalls {
Expand Down Expand Up @@ -1190,4 +1213,8 @@ - (BOOL)isBatchActive {
return _wasBatchActive;
}

- (void)updateNativeInfoToHippyGlobalObject:(NSDictionary *)nativeInfo {
[self.javaScriptExecutor updateNativeInfoToHippyGlobalObject:nativeInfo];
}

@end
Loading

0 comments on commit a6b1877

Please sign in to comment.