diff --git a/docs/en-us/ios/integration.md b/docs/en-us/ios/integration.md index 7bad22fd8cf..b4cc65a438f 100644 --- a/docs/en-us/ios/integration.md +++ b/docs/en-us/ios/integration.md @@ -1,89 +1,139 @@ -# iOS Integration +# iOS integration -> Note: the following documents assume that you have some experience in iOS development. +> Note: The following documents assume that you already have some experience in iOS development. -This tutorial shows how to integrate Hippy into an iOS project. +This tutorial describes how to integrate Hippy into an existing iOS project. --- -# Integrate with Cocoapods +## 1. Use Cocoapods to integrate iOS SDK -1. install [cocoapods](https://cocoapods.org/), Hippy iOS SDK [version query](https://cocoapods.org/pods/hippy) +[CocoaPods](https://cocoapods.org/) is a popular package management tool for iOS and macOS development. We'll use this to add Hippy's iOS Framework to an existing iOS project. -2. Create a podfile file under user-defined project directory with the following text +It is recommended to use Homebrew to install CocoaPods. The installation command is as follows: - ```text - # keep podfile directory structure - install! "cocoapods", :preserve_pod_file_structure => true - platform :ios, '11.0' - # replace TargetName with user's project name - target TargetName do - # use latest version of Hippy - pod 'hippy' - # if you want to assign Hippy version, say, 2.0.0 - #pod 'hippy', '2.0.0' - end - ``` +```shell +brew install cocoapods +``` - > Tip: When integrating versions `2.13.0` to `2.16.x`, if you access hippy in the form of a static link library, you need to set the `force_load` compilation parameter to load all symbols of hippy. - > - > `2.17.x` and above versions do not need to be configured. - > - > There are many ways to set `force_load`, you can choose any of the following configurations, and adjust according to the actual situation: - > - > * Directly set `*-force_load "${PODS_CONFIGURATION_BUILD_DIR}/hippy/libhippy.a"*` in the configuration of `Other Linker Flags` in the Build Settings of the target corresponding to the main project. - > - > * Add `post_install hook` in the Podfile configuration file of the App project, and add `force_load` to xcconfig by yourself. - > +> Of course, it is possible to integrate Hippy iOS Framework without using CocoaPods, but this will complicate the integration process. You need to manually package, add libraries, and set necessary link parameters to existing projects. -3. Execute in the command line +The specific steps are as follows: - ```text - pod install - ``` +1. First, determine the Hippy iOS SDK version to be integrated ([version query address](https://github.com/Tencent/Hippy/releases)), and record it for subsequent use -4. open the project by the `.xcworkspace` file generated by cocoapods. +2. Secondly, prepare the Podfile file of the existing iOS project -# Write Code to Start Debugging or Load Business Code + The Podfile file is the configuration file of the CocoaPods package management tool. If the current project does not have this file, the simplest way to create it is to use the CocoaPods init command and execute the following command in the iOS project file directory: -Hippy provides a code-splitting loading interface and a non-code-splitting loading interface. All service packages are carried through `HippyRootView`. Creating a business is to create a `RootView`. + ```shell + pod init + ``` -## Using the code-splitting load interface + The generated Podfile will contain some demo settings that you can adjust according to the purpose of the integration. Ultimately, the Podfile should look like this: -``` objectivec -/** This method is suitable for the following scenarios. - * Prepare the JS environment and load package 1 before the business is started, and load package 2 when the business is started to reduce package loading time - * We suggest package 1 as the base package, which is not related to the business and contains only some common base components, common to all businesses - * Package 2 is loaded as business code -*/ + ```text + platform:ios, '11.0' -// Load package 1 address first to create execution environment -//commonBundlePath being package 1's path -NSURL * commonBundlePath = getCommonBundlePath(); -HippyBridge *bridge = [[HippyBridge alloc] initWithBundleURL: commonBundlePath - moduleProvider: nil - launchOptions: nil]; - -// Create rootview by bridge and package2 address -- (instancetype)initWithBridge:(HippyBridge *)bridge - businessURL:(NSURL *)businessURL // business package address - moduleName:(NSString *)moduleName // business package startup function name - initialProperties:(NSDictionary *)initialProperties // initialize parameters - shareOptions:(NSDictionary *)shareOptions // configuration parameters (advanced) - isDebugMode:(BOOL)isDebugMode // whether debug mode - delegate:(id)delegate // rootview load callback + # TargetName is most likely your project name + targetTargetName do -``` + # Specify here the hippy version number recorded in step 1 + pod 'hippy', 'your_specified_version' + + end + ``` + + > IMPORTANT NOTE: + > + > When integrating some historical versions from `2.13.0` to `2.16.x`, if hippy is accessed in the form of a static link library, the `force_load` compilation parameter needs to be set to load all symbols of hippy, otherwise the Hippy application will not be able to run. The versions that need to be set are as follows: + > + > `2.13.0` to `2.13.13` + > + > `2.14.0` to `2.14.10` + > + > `2.15.0` to `2.15.7` + > + > `2.16.0` to `2.16.5` + > + > `force_load` can be set in a variety of ways. You can choose any of the following configurations and adjust according to the actual situation: + > + > * Add `*-force_load "${PODS_CONFIGURATION_BUILD_DIR}/hippy/libhippy.a"*` directly to the Build Settings - `Other Linker Flags` configuration of the corresponding target of the main project. + > + > * Add `post_install hook` to the Podfile configuration file of the App project, and add `force_load` to xcconfig by yourself. + > + +3. Finally, execute in the command line + + ```shell + pod install + ``` + + When the command is successfully executed, use the project file with the `.xcworkspace` suffix generated by CocoaPods to open the project. + +## 2. Write SDK access code and load local or remote Hippy resource package -## Using the non-code-splitting load interface +The initialization of Hippy SDK only requires two steps: -``` objectivec -Subpackage loading interface - (instancetype)initWithBundleURL:(NSURL *)bundleURL // package address - moduleName:(NSString *)moduleName // business package startup function name - initialProperties:(NSDictionary *)initialProperties // initialize parameters - shareOptions:(NSDictionary *)shareOptions // configuration parameters (advanced) - isDebugMode:(BOOL)isDebugMode // whether debug mode - delegate:(id )delegate // rootview load callback +1. Initialize a HippyBridge instance. HippyBridge is the most important concept of Hippy. It is a bridge for communication between the Native side and the JS side. It also carries the main context information of the Hippy application. + +2. Initialize a HippyRootView instance through the HippyBridge instance. HippyRootView is another important concept of Hippy applications. Hippy applications will be displayed by it. Therefore, it can be said that creating a business means creating a `HippyRootView`. + +Currently, Hippy provides subcontracted loading interfaces and non-subcontracted loading interfaces. The usage methods are as follows: + +### Method 1. Use subcontracting loading interface + +```objective +/** This method is suitable for the following scenarios: + * Prepare the JS environment before the business starts, and load package 1. When the business starts, load package 2 to reduce package loading time. + * We recommend package 1 as a basic package, which has nothing to do with the business. It only contains some common basic components and is common to all businesses. + * Package 2 is loaded as business code +*/ + +// First load package 1 and create a HippyBridge instance +// Assume commonBundlePath is the path of package 1 +// Tips: For detailed parameter description, please refer to the header file: HippyBridge.h +NSURL *commonBundlePath = getCommonBundlePath(); +HippyBridge *bridge = [[HippyBridge alloc] initWithDelegate:self + bundleURL:commonBundlePath + moduleProvider:nil + launchOptions:your_launchOptions + executorKey:nil]; + +// Then create a HippyRootView instance through the above bridge and package 2 address +// Assume businessBundlePath is the path of package 2 +// Tips: For detailed parameter description, please refer to the header file: HippyRootView.h +HippyRootView *rootView = [[HippyRootView alloc] initWithBridge:bridge + businessURL:businessBundlePath + moduleName:@"Your_Hippy_App_Name" + initialProperties:@{} + shareOptions:nil + delegate:nil]; + +// Finally, set the frame for the generated rootView and mount it on the specified VC. +rootView.frame = self.view.bounds; +rootView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; +[self.view addSubview:rootView]; + +// At this point, you have completed the initialization of a Hippy application. The SDK will automatically load resources and start running the Hippy application. +``` + +### Method 2. Use non-packaging loading interface + +```objective +//Similar to the above-mentioned use of the subcontracted loading interface, you first need to create a HippyBridge instance. +// The difference is that when creating a HippyRootView instance, there is no need to pass in the business package, that is, businessBundlePath. You can create it directly using the following interface. +// Tips: For detailed parameter description, please refer to the header file: HippyRootView.h +- (instancetype)initWithBridge:(HippyBridge *)bridge + moduleName:(NSString *)moduleName + initialProperties:(nullable NSDictionary *)initialProperties + shareOptions:(nullable NSDictionary *)shareOptions + delegate:(nullable id)delegate; ``` -!> Regardless of whether rootview is initialized with or without code-splitting, if **isdebugmode** is YES, all parameters will be ignored and the test dataset is loaded directly using the npm local service. Using code-splitting loading can be combined with a series of strategies, such as pre-loading bridge, global single bridge, and so on, to optimize page opening speed. +> A simple sample project is provided in the Hippy repository, including all the above access codes, as well as more notes. +> +> It is recommended to refer to this example to complete the integration of the SDK into existing projects: [iOS Demo](https://github.com/Tencent/Hippy/tree/master/examples/ios-demo) +> + +!> Using subpackage loading, you can combine a series of strategies, such as preloading bridge in advance, global single bridge, etc. to optimize page opening speed. diff --git a/docs/ios/integration.md b/docs/ios/integration.md index 7091386eb00..12755946224 100644 --- a/docs/ios/integration.md +++ b/docs/ios/integration.md @@ -2,32 +2,59 @@ > 注:以下文档都是假设您已经具备一定的 iOS 开发经验。 -这篇教程,讲述了如何将 Hippy 集成到 iOS 工程。 +这篇教程,讲述了如何将 Hippy 集成到现有的 iOS 工程。 --- -# 使用 Cocoapods 集成 +## 一、使用 Cocoapods 集成 iOS SDK -1. 安装 [CocoaPods](https://cocoapods.org/),Hippy iOS SDK [版本查询](https://cocoapods.org/pods/hippy) +[CocoaPods](https://cocoapods.org/) 是一个iOS和macOS开发中流行的包管理工具。我们将使用它把Hippy的iOS Framework添加到现有iOS项目中。 -2. 在用户自定义工程目录下创建 podfile 文件,文本如下 +推荐使用Homebrew安装CocoaPods,安装命令如下: + +```shell +brew install cocoapods +``` + +> 当然,也可以不使用CocoaPods来集成 Hippy iOS Framework,但这样会使集成过程变得复杂,您需要手动打包、添加库以及设置必要的链接参数到现有项目中。 + +具体的操作步骤如下: + +1. 首先,确定要集成的Hippy iOS SDK版本([版本查询地址](https://github.com/Tencent/Hippy/releases)),并记录以备后续使用 + +2. 其次,准备好现有iOS工程的 Podfile 文件 + + Podfile 文件是CocoaPods包管理工具的配置文件,如果当前工程还没有该文件,最简单的创建方式是通过CocoaPods init命令,在iOS工程文件目录下执行如下命令: + + ```shell + pod init + ``` + + 生成的Podfile将包含一些demo设置,您可以根据集成的目的对其进行调整。最终,Podfile应该看起来像这样: ```text - #保持pod文件目录结构 - install! "cocoapods", :deterministic_uuids => false platform :ios, '11.0' - #TargetName替换成用户工程名 + + # TargetName大概率是您的项目名称 target TargetName do - #使用hippy最新版本 - pod 'hippy' - #若想指定使用的hippy版本号,比如2.0.0版,请使用 - #pod 'hippy', '2.0.0' + + # 在此指定步骤1中记录的hippy版本号 + pod 'hippy', 'your_specified_version' + end ``` - > 提示:集成`2.13.0`至`2.16.x`版本时,如以静态链接库形式接入hippy,需设置`force_load`编译参数来加载hippy所有符号。 + > 重要提示: + > + > 集成`2.13.0`至`2.16.x`部分历史版本时,如以静态链接库形式接入hippy,需设置`force_load`编译参数来加载hippy所有符号, 否则将无法运行Hippy应用。需设置的版本如下: + > + > `2.13.0` 至 `2.13.13` > - > `2.17.x`及以上版本无需配置。 + > `2.14.0` 至 `2.14.10` + > + > `2.15.0` 至 `2.15.7` + > + > `2.16.0` 至 `2.16.5` > > 可通过多种方式实现设置`force_load`,可选如下任意一项进行配置,并结合实际情况自行调整: > @@ -36,19 +63,25 @@ > * 在App工程的 Podfile 配置文件中添加 `post_install hook`,自行给 xcconfig 添加 `force_load`。 > -3. 在命令行中执行 +3. 最后,在命令行中执行 - ```text + ```shell pod install ``` -4. 使用 cocoapods 生成的 `.xcworkspace` 后缀名的工程文件来打开工程。 + 当命令成功执行完后,使用 CocoaPods 生成的 `.xcworkspace` 后缀名的工程文件来打开工程。 -# 编写代码开始调试或者加载业务代码 +## 二、编写SDK接入代码,加载本地或远程的Hippy资源包 -Hippy 提供分包加载接口以及不分包加载接口, 所有的业务包都是通过 `HippyRootView` 进行承载,创建业务也就是创建 `RootView`。 +Hippy SDK的初始化简单来说只需两步: -## 使用分包加载接口 +1、初始化一个HippyBridge实例,HippyBridge是Hippy最重要的概念,它是Native侧与JS侧进行通信的`桥梁`,同时也承载了Hippy应用的主要上下文信息。 + +2、通过HippyBridge实例初始化一个HippyRootView实例,HippyRootView是Hippy应用另一个重要概念,Hippy应用将由它显示出来,因此可以说创建业务也就是创建一个 `HippyRootView`。 + +目前,Hippy 提供了分包加载接口以及不分包加载接口,使用方式分别如下: + +### 方式1. 使用分包加载接口 ``` objectivec /** 此方法适用于以下场景: @@ -57,33 +90,50 @@ Hippy 提供分包加载接口以及不分包加载接口, 所有的业务包都 * 包2作为业务代码加载 */ -//先加载包1地址,创建执行环境 -//commonBundlePath值包1路径 -NSURL * commonBundlePath = getCommonBundlePath(); -HippyBridge *bridge = [[HippyBridge alloc] initWithBundleURL: commonBundlePath - moduleProvider: nil - launchOptions: nil]; - -// 通过bridge以及包2地址创建rootview -- (instancetype)initWithBridge:(HippyBridge *)bridge - businessURL:(NSURL *)businessURL // 业务包地址 - moduleName:(NSString *)moduleName // 业务包启动函数名 - initialProperties:(NSDictionary *)initialProperties // 初始化参数 - shareOptions:(NSDictionary *)shareOptions // 配置参数(进阶) - isDebugMode:(BOOL)isDebugMode // 是否是调试模式 - delegate:(id)delegate // rootview加载回调 - +// 先加载包1,创建出一个HippyBridge实例 +// 假设commonBundlePath为包1的路径 +// Tips:详细参数说明请查阅头文件: HippyBridge.h +NSURL *commonBundlePath = getCommonBundlePath(); +HippyBridge *bridge = [[HippyBridge alloc] initWithDelegate:self + bundleURL:commonBundlePath + moduleProvider:nil + launchOptions:your_launchOptions + executorKey:nil]; + +// 再通过上述bridge以及包2地址创建HippyRootView实例 +// 假设businessBundlePath为包2的路径 +// Tips:详细参数说明请查阅头文件: HippyRootView.h +HippyRootView *rootView = [[HippyRootView alloc] initWithBridge:bridge + businessURL:businessBundlePath + moduleName:@"Your_Hippy_App_Name" + initialProperties:@{} + shareOptions:nil + delegate:nil]; + +// 最后,给生成的rootView设置好frame,并将其挂载到指定的VC上。 +rootView.frame = self.view.bounds; +rootView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; +[self.view addSubview:rootView]; + +// 至此,您已经完成一个Hippy应用的初始化,SDK内部将自动加载资源并开始运行Hippy应用。 ``` -## 使用不分包加载接口 +### 方式2. 使用不分包加载接口 ``` objectivec -- (instancetype)initWithBundleURL:(NSURL *)bundleURL // 包地址 - moduleName:(NSString *)moduleName // 业务包启动函数名 - initialProperties:(NSDictionary *)initialProperties // 初始化参数 - shareOptions:(NSDictionary *)shareOptions // 配置参数(进阶) - isDebugMode:(BOOL)isDebugMode // 是否是调试模式 - delegate:(id )delegate // rootview加载回调 +// 与上述使用分包加载接口类似,首先需要创建一个HippyBridge实例, +// 区别是在创建HippyRootView实例时,无需再传入业务包,即businessBundlePath,直接使用如下接口创建即可 +// Tips:详细参数说明请查阅头文件: HippyRootView.h +- (instancetype)initWithBridge:(HippyBridge *)bridge + moduleName:(NSString *)moduleName + initialProperties:(nullable NSDictionary *)initialProperties + shareOptions:(nullable NSDictionary *)shareOptions + delegate:(nullable id)delegate; ``` -!> 不管使用分包还是不分包初始化 rootview, 如果 **isDebugMode** 为YES的情况下,会忽略所有参数,直接使用 npm 本地服务加载测试 bundle。使用分包加载可以结合一系列策略,比如提前预加载bridge, 全局单bridge等来优化页面打开速度。 +> 在Hippy 仓库中提供了一个简易示例项目,包含上述全部接入代码,以及更多注意事项。 +> +> 建议参考该示例完成SDK到已有项目的集成:[iOS Demo](https://github.com/Tencent/Hippy/tree/master/examples/ios-demo) +> + +!> 使用分包加载可以结合一系列策略,比如提前预加载bridge, 全局单bridge等来优化页面打开速度。 diff --git a/examples/ios-demo/HippyDemo/ViewController.m b/examples/ios-demo/HippyDemo/ViewController.m index d5dbdd408bd..b82a9ac9d93 100644 --- a/examples/ios-demo/HippyDemo/ViewController.m +++ b/examples/ios-demo/HippyDemo/ViewController.m @@ -84,7 +84,6 @@ - (void)viewDidLoad { businessURL:[NSURL fileURLWithPath:businessBundlePath] moduleName:@"Demo" initialProperties:@{@"isSimulator": @(isSimulator)} - launchOptions:nil shareOptions:nil delegate:nil]; #endif diff --git a/ios/sdk/base/HippyBridge.h b/ios/sdk/base/HippyBridge.h index 1f436d7f663..dba20b110f3 100644 --- a/ios/sdk/base/HippyBridge.h +++ b/ios/sdk/base/HippyBridge.h @@ -95,20 +95,27 @@ HIPPY_EXTERN NSString *HippyBridgeModuleNameForClass(Class bridgeModuleClass); */ @interface HippyBridge : NSObject -/** - * Creates a new bridge with a custom HippyBridgeDelegate. - * - * All the interaction with the JavaScript context should be done using the bridge - * instance of the HippyBridgeModules. Modules will be automatically instantiated - * using the default contructor, but you can optionally pass in an array of - * pre-initialized module instances if they require additional init parameters - * or configuration. - */ +/// Create A HippyBridge instance with a common js bundle. +/// +/// @param delegate bridge delegate +/// @param bundleURL the +/// @param block for user-defined module +/// @param launchOptions launch options, will not be sent to frontend +/// @param executorKey key to engine instance. HippyBridge with same engine key will share same engine intance. +/// +/// Note: 多个bridge使用相同的共享engineKey时,只有全部bridge实例销毁时engine资源才将释放,因此,请注意合理使用,避免出现意外的内存泄漏。 +/// 传空时默认不共享,SDK内部默认分配一随机key。 +/// +/// * All the interaction with the JavaScript context should be done using the bridge +/// * instance of the HippyBridgeModules. Modules will be automatically instantiated +/// * using the default contructor, but you can optionally pass in an array of +/// * pre-initialized module instances if they require additional init parameters +/// * or configuration. - (instancetype)initWithDelegate:(id)delegate - bundleURL:(NSURL *)bundleURL + bundleURL:(nullable NSURL *)bundleURL moduleProvider:(nullable HippyBridgeModuleProviderBlock)block - launchOptions:(NSDictionary *)launchOptions - executorKey:(NSString *)executorKey; + launchOptions:(nullable NSDictionary *)launchOptions + executorKey:(nullable NSString *)executorKey; #pragma mark - diff --git a/ios/sdk/base/HippyRootView.h b/ios/sdk/base/HippyRootView.h index 7e7d36078b6..66afba43370 100644 --- a/ios/sdk/base/HippyRootView.h +++ b/ios/sdk/base/HippyRootView.h @@ -21,11 +21,12 @@ */ #import - #import "HippyBridge.h" @protocol HippyRootViewDelegate; +NS_ASSUME_NONNULL_BEGIN + /** * This enum is used to define size flexibility type of the root view. * If a dimension is flexible, the view will recalculate that dimension @@ -54,22 +55,42 @@ extern NSString *const HippyContentDidAppearNotification; */ @interface HippyRootView : UIView +/// Create HippyRootView instance +/// +/// @param bridge the hippyBridge instance +/// @param moduleName module name +/// @param initialProperties application properties, see appProperties property. +/// @param shareOptions Shared data between different rootViews on same bridge. +/// @param delegate HippyRootViewDelegate +/// +/// Note: shareOptions will not sent to the front end. +/// - (instancetype)initWithBridge:(HippyBridge *)bridge moduleName:(NSString *)moduleName - initialProperties:(NSDictionary *)initialProperties - shareOptions:(NSDictionary *)shareOptions - delegate:(id)delegate; + initialProperties:(nullable NSDictionary *)initialProperties + shareOptions:(nullable NSDictionary *)shareOptions + delegate:(nullable id)delegate; -/** - * - Convenience initializer - */ + +/// Create HippyRootView instance +/// & Load the business BundleURL +/// & Run application +/// +/// @param bridge the hippyBridge instance +/// @param businessURL the bundleURL to load +/// @param moduleName module name +/// @param initialProperties application properties, see appProperties property. +/// @param shareOptions Shared data between different rootViews on same bridge. +/// @param delegate HippyRootViewDelegate +/// +/// Note: shareOptions will not sent to the front end. +/// - (instancetype)initWithBridge:(HippyBridge *)bridge businessURL:(NSURL *)businessURL moduleName:(NSString *)moduleName - initialProperties:(NSDictionary *)initialProperties - launchOptions:(NSDictionary *)launchOptions - shareOptions:(NSDictionary *)shareOptions - delegate:(id)delegate; + initialProperties:(nullable NSDictionary *)initialProperties + shareOptions:(nullable NSDictionary *)shareOptions + delegate:(nullable id)delegate; /** * The name of the JavaScript module to execute within the @@ -180,3 +201,5 @@ extern NSString *const HippyContentDidAppearNotification; @end + +NS_ASSUME_NONNULL_END diff --git a/ios/sdk/base/HippyRootView.mm b/ios/sdk/base/HippyRootView.mm index f71aa7117ae..744fd26e3c7 100644 --- a/ios/sdk/base/HippyRootView.mm +++ b/ios/sdk/base/HippyRootView.mm @@ -134,7 +134,6 @@ - (instancetype)initWithBridge:(HippyBridge *)bridge businessURL:(NSURL *)businessURL moduleName:(NSString *)moduleName initialProperties:(NSDictionary *)initialProperties - launchOptions:(NSDictionary *)launchOptions shareOptions:(NSDictionary *)shareOptions delegate:(id)delegate { NSParameterAssert(bridge); @@ -175,6 +174,10 @@ - (UIViewController *)hippyViewController { return _hippyViewController ?: [super hippyViewController]; } +- (UIView *)contentView { + return _contentView; +} + - (BOOL)canBecomeFirstResponder { return YES; }