Skip to content

Commit

Permalink
Merge branch 'main' into feature/css_scoped
Browse files Browse the repository at this point in the history
  • Loading branch information
open-hippy authored Dec 22, 2023
2 parents 54ba2f5 + 0807923 commit c29e34a
Show file tree
Hide file tree
Showing 16 changed files with 235 additions and 126 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ class DevToolsUtil {

static void PostDomTask(const std::weak_ptr<DomManager>& weak_dom_manager, std::function<void()> func);

static bool ShouldAvoidPostDomManagerTask(const std::string& event_name);

private:
static std::shared_ptr<DomNode> GetHitNode(const std::shared_ptr<DomNode>& root_node, const std::shared_ptr<DomNode>& node, double x, double y);
static bool IsLocationHitNode(const std::shared_ptr<DomNode>& root_node, const std::shared_ptr<DomNode>& dom_node, double x, double y);
Expand Down
9 changes: 9 additions & 0 deletions devtools/devtools-integration/native/src/devtools_utils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -413,4 +413,13 @@ void DevToolsUtil::PostDomTask(const std::weak_ptr<DomManager>& weak_dom_manager
dom_manager->PostTask(hippy::dom::Scene(std::move(ops)));
}
}

/**
* Specific methods like getLocationOnScreen should wait in the dom manager task runner. To avoid a deadlock, the
* callback must not be posted in the same task runner.
*/
bool DevToolsUtil::ShouldAvoidPostDomManagerTask(const std::string& event_name) {
return event_name == kGetLocationOnScreen;
}

} // namespace hippy::devtools
1 change: 1 addition & 0 deletions docs/development/_sidebar.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* [Demo体验](development/demo.md)
* [前端接入](development/web-integration.md)
* [环境搭建](development/native-integration.md)
* [3.0升级指引](development/android-3.0-upgrade-guidelines.md)
* [自定义组件](development/native-component.md)
* [自定义模块](development/native-module.md)
* [事件](development/native-event.md)
Expand Down
89 changes: 89 additions & 0 deletions docs/development/android-3.0-upgrade-guidelines.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Android 3.0 SDK 升级指引

>这篇教程,主要介绍Hippy 2.0升级3.0版本如何进行适配以及2.0和3.0在使用上的一些差异化。
</br>
1. 废弃HippyImageLoader相关实现

HippyImageLoader在2.0中作为引擎初始化必设项是不合理的,在3.0版本中由于图片数据的网络拉取和解码解耦为不同的子模块,HippyImageLoader已经被移除,图片请求会和其它所有IO相关的资源请求统一走vfs模块进行分发,网络请求vfs最终会分发到HttpAdapter完成请求的处理。
获取到图片数据后,解码模块新增加ImageDecoderAdapter可选项设置(引擎初始化时候新增imageDecoderAdapter参数设置),用于支持开发者有自定义格式图片的解码需求,ImageDecoderAdapter的具体接口描述如下:

```java
// 解码image原始数据,解码的结果可以通过 image data holder提供的setBitmap或者setDrawable接口
// 置到holder中,如果宿主decode adapter不处理,返回false由SDK走默认解码逻辑
boolean preDecode(@NonNull byte[] data,
@Nullable Map<String, Object> initProps,
@NonNull ImageDataHolder imageHolder,
@NonNull BitmapFactory.Options options);

// 解码结束后,宿主通过该接口回调还可以获得二次处理bitmap的机会,比如要对bitmap做高斯模糊。
void afterDecode(@Nullable Map<String, Object> initProps,
@NonNull ImageDataHolder imageHolder,
@NonNull BitmapFactory.Options options);

// 引擎退出销毁时调用,释放adapter可能占用的资源
void destroyIfNeeded();
```

2. 引擎初始化完成callback线程变更

2.0中initEngine初始化结果SDK内部会切换到UI线程再callback onInitialized给宿主,但我们发现在很多APP内业务反馈的使用场景下,callback切UI线程执行具有很大的延迟,所以3.0中callback onInitialized直接在子线程回调并继续执行loadModule会有更好的效率,之前2.0在callback中对hippyRootView相关的UI操作需要开发者自己来切UI线程保证。

3. 引擎销毁

3.0中destroyModule增加了回调接口,destroyEngine需要等destroyModule执行完成回调以后才能调用,否则可能有CRASH的风险,宿主可以参考下面代码示例进行引擎销毁:

```java
fun destroyEngine(hippyEngine: HippyEngine?, hippyRootView: ViewGroup?) {
hippyEngine?.destroyModule(hippyRootView,
Callback<Boolean> { result, e -> hippyEngine.destroyEngine() })
}
```

4. HippyEngine中的接口不再直接引用HippyRootView

destroyModule接口参数以及loadModule接口返回值均使用系统ViewGroup类型替代,尽量减少对SDK的耦合。

5. loadModule接口参数ModuleListener接口有所变更
- 我们发现之前2.0在onLoadCompleted回调接口中返回的root view参数其实在各多业务场景都不会去用到,所以在3.0中我们简化了这个接口,移除了root view参数的返回
- 增加onFirstViewAdded接口回调,返回第一view挂载到Hippy root view的回调时机

6. 引擎初始化参数增加资源请求自定义processor的设置

```java
public List<Processor> processors;
```

关于vfs特性以及Processor接口使用的介绍可以详见 [VFS](feature/feature3.0/vfs.md)。

7. 关于UI Component事件发送
Hippy终端事件的发送分为全局事件和UI Component事件2种,全局事件和2.0保持一致,使用HippyEngine中暴露的sendEvent接口发送,而UI Component事件的发送可以使用在3.0新增工具类EventUtils中封装的事件发送接口:

```java
@MainThread
public static void sendComponentEvent(@Nullable View view,
@NonNull String eventName,
@Nullable Object params);
```

8. HippyInstanceContext已经被废弃
2.0中基于系统ContextWrapper封了Hippy自己的HippyInstanceContext,并将其作为所有Hippy view的初始化参数,随着3.0 framework和renderer两个子模块的解耦,我们发现HippyInstanceContext设计过于臃肿,已经不再适用于最新的3.0架构,所以我们在最新的3.0版本中废弃了HippyInstanceContext,改用更加轻量化的NativeRenderContext取代,也就是说3.0中所有Hippy相关的view中保存的context都是NativeRenderContext类型。

9. HippyEngine中新增render node缓存特性接口
2.0中我们支持了dom node缓存特性,但dom node缓存针对复杂页面场景性能还是存在一定的性能瓶颈,所有我们在3.0重新实现了性能更好的render node缓存特性,关于render node缓存特性与接口使用的介绍可以详见 [RenderNode Snapshot](feature/feature3.0/render-node-snapshot.md)。

10. 关于自定义UI组件的Controller中dispatchFunction参数说明
2.0中dispatchFunction接收事件属性的参数类型为HippyArray类型,由于在2.0的后续版本中HippyMapHippyArray就已经被标记为@Deprecated,所以在3.0的重构中,SDK内部也逐渐替换一些使用HippyMapHippyArray类型参数的接口,所以针对Controller的dispatchFunction接口SDK内部默认替换成List类型参数

```java
public void dispatchFunction(@NonNull T view,
@NonNull String functionName,
@NonNull List params);

public void dispatchFunction(@NonNull T view,
@NonNull String functionName,
@NonNull List params,
@NonNull Promise promise);
```

为了减低3.0升级的成本原来使用HippyArray类型的接口还是保留,只是标记为@Deprecated,所以升级3.0对于原来定义的dispatchFunction接口不需要做任何修改,但建议后续升级到3.0版本的同学,定义新UI组件的时候,直接Override使用List参数类型的新接口。
26 changes: 0 additions & 26 deletions docs/development/native-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,31 +58,6 @@

4. 在宿主 APP 工程中增加引擎初始化与 `hippyRootView` 挂载逻辑,具体可以参考 [Demo](https://github.com/Tencent/Hippy/tree/v3.0-dev/framework/examples/android-demo) 工程中 `HippyEngineWrapper` 实现

## 3.0与2.0的接入区别

1. 引擎初始化参数

HippyImageLoader在2.0中是必设项,在最新3.0版本中由于图片数据的网络拉取和图片解码解耦为不同的子模块,HippyImageLoader已经被移除,新增加ImageDecoderAdapter可选项设置,用于支持开发者有自定义格式图片的解码需求,ImageDecoderAdapter的具体接口用法可以参考native renderer文档介绍

2. 引擎初始化完成callback线程变更

2.0中initEngine初始化结果SDK内部会切换到UI线程再callback给宿主,但我们发现在部分APP启动就使用Hippy的场景下,callback切UI线程执行具有很大的延迟,所以3.0中callback直接在子线程回调,之前2.0在callback中对hippyRootView相关的UI操作需要开发者自己来切UI线程保证

3. 引擎销毁

3.0中destroyModule增加了回调接口,destroyEngine需要等destroyModule执行完成回调以后才能调用,否则可能有CRASH的风险

4. HippyEngine中不再直接引用HippyRootView

destroyModule接口参数以及loadModule接口返回值均使用系统ViewGroup类型替代,尽量减少对SDK的耦合

5. loadModule接口参数ModuleListener接口有所变更
- onLoadCompleted回调接口remove root view参数
- 增加onFirstViewAdded接口回调

<br/>
<br/>

# iOS

>注:以下文档都是假设您已经具备一定的 iOS 开发经验。
Expand Down Expand Up @@ -777,4 +752,3 @@ engine.start({
},
});
```

Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,7 @@ public HttpTaskCallbackImpl(@NonNull ResourceDataHolder holder,
@Override
public void onTaskSuccess(HippyHttpRequest request, HippyHttpResponse response)
throws Exception {
mDataHolder.resultCode = FetchResultCode.OK.ordinal();
mDataHolder.addResponseHeaderProperty(HTTP_RESPONSE_STATUS_CODE,
response.getStatusCode().toString());
mDataHolder.addResponseHeaderProperty(HTTP_RESPONSE_RESPONSE_MESSAGE,
Expand All @@ -355,7 +356,6 @@ public void onTaskSuccess(HippyHttpRequest request, HippyHttpResponse response)
}
mDataHolder.errorMessage = sb.toString();
}
mDataHolder.resultCode = FetchResultCode.ERR_REMOTE_REQUEST_FAILED.ordinal();
mCallback.onHandleCompleted();
return;
}
Expand All @@ -365,7 +365,6 @@ public void onTaskSuccess(HippyHttpRequest request, HippyHttpResponse response)
}
mDataHolder.readResourceDataFromStream(inputStream);
} catch (IOException e) {
mDataHolder.resultCode = FetchResultCode.ERR_REMOTE_REQUEST_FAILED.ordinal();
mDataHolder.errorMessage = e.getMessage();
mCallback.onHandleCompleted();
return;
Expand Down Expand Up @@ -397,7 +396,6 @@ public void onTaskSuccess(HippyHttpRequest request, HippyHttpResponse response)
cookieManager.flush();
}
}
mDataHolder.resultCode = FetchResultCode.OK.ordinal();
mCallback.onHandleCompleted();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,18 +102,19 @@ protected void normalizeRequest(@NonNull HippyMap request,
}
}

protected void handleFetchResponse(@NonNull ResourceDataHolder dataHolder, Promise promise)
@NonNull
protected JSObject handleFetchResponse(@NonNull ResourceDataHolder dataHolder)
throws IllegalStateException {
JSObject responseObject = new JSObject();
int statusCode = 0;
int statusCode = -1;
String responseMessage = null;
JSObject headerObject = new JSObject();
if (dataHolder.responseHeaders != null) {
try {
statusCode = Integer.parseInt(
dataHolder.responseHeaders.get(HTTP_RESPONSE_STATUS_CODE));
} catch (NumberFormatException e) {
throw new IllegalStateException(e.getMessage());
throw new IllegalStateException("parse status code error!");
}
responseMessage = dataHolder.responseHeaders.get(HTTP_RESPONSE_RESPONSE_MESSAGE);
for (Entry<String, String> entry : dataHolder.responseHeaders.entrySet()) {
Expand All @@ -125,8 +126,11 @@ protected void handleFetchResponse(@NonNull ResourceDataHolder dataHolder, Promi
headerObject.set(key, value);
}
}
if (responseMessage == null) {
responseMessage = (dataHolder.errorMessage == null) ? "" : dataHolder.errorMessage;
}
responseObject.set(HTTP_RESPONSE_STATUS_CODE, statusCode);
responseObject.set("statusLine", (responseMessage == null) ? "" : responseMessage);
responseObject.set("statusLine", responseMessage);
responseObject.set("respHeaders", headerObject);
String body = "";
try {
Expand All @@ -138,7 +142,22 @@ protected void handleFetchResponse(@NonNull ResourceDataHolder dataHolder, Promi
throw new IllegalStateException(e.getMessage());
}
responseObject.set("respBody", body);
promise.resolve(responseObject);
return responseObject;
}

protected void handleFetchResult(@NonNull ResourceDataHolder dataHolder, final Promise promise) {
try {
if (dataHolder.resultCode == ResourceDataHolder.RESOURCE_LOAD_SUCCESS_CODE) {
JSObject responseObject = handleFetchResponse(dataHolder);
promise.resolve(responseObject);
} else {
String errorMessage =
(dataHolder.errorMessage == null) ? "Load remote resource failed!" : dataHolder.errorMessage;
promise.reject(errorMessage);
}
} catch (IllegalStateException e) {
promise.reject("Handle response failed: " + e.getMessage());
}
}

@SuppressWarnings("deprecation")
Expand All @@ -162,19 +181,7 @@ public void fetch(final HippyMap request, final Promise promise) {
new FetchResourceCallback() {
@Override
public void onFetchCompleted(@NonNull ResourceDataHolder dataHolder) {
if (dataHolder.resultCode
== ResourceDataHolder.RESOURCE_LOAD_SUCCESS_CODE) {
try {
handleFetchResponse(dataHolder, promise);
} catch (IllegalStateException e) {
promise.reject(
"Handle response failed: " + e.getMessage());
}
} else {
String error = TextUtils.isEmpty(dataHolder.errorMessage)
? "Load remote resource failed!" : dataHolder.errorMessage;
promise.resolve(error);
}
handleFetchResult(dataHolder, promise);
dataHolder.recycle();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,6 @@ - (void)runHippyDemo {
moduleProvider:nil
launchOptions:launchOptions
executorKey:uniqueEngineKey];
_hippyBridge.contextName = uniqueEngineKey;
_hippyBridge.moduleName = @"Demo";
_hippyBridge.methodInterceptor = self;

[_hippyBridge setInspectable:YES];
Expand Down
6 changes: 4 additions & 2 deletions framework/ios/base/HippyDisplayLink.m
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,13 @@
#import "HippyDisplayLink.h"

#import <Foundation/Foundation.h>
#import <QuartzCore/CADisplayLink.h>
#import <QuartzCore/QuartzCore.h>

#import "HippyAssert.h"
#import "HippyBridgeModule.h"
#import "HippyFrameUpdate.h"
#import "HippyModuleData.h"
#import "HippyWeakProxy.h"

#define HippyAssertRunLoop() HippyAssert(_runLoop == [NSRunLoop currentRunLoop], @"This method must be called on the CADisplayLink run loop")

Expand All @@ -41,7 +42,8 @@ @implementation HippyDisplayLink {
- (instancetype)init {
if ((self = [super init])) {
_frameUpdateObservers = [NSMutableSet new];
_jsDisplayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(_jsThreadUpdate:)];
HippyWeakProxy *weakProxy = [HippyWeakProxy weakProxyForObject:self];
_jsDisplayLink = [CADisplayLink displayLinkWithTarget:weakProxy selector:@selector(_jsThreadUpdate:)];
}

return self;
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 @@ -139,7 +139,7 @@ HIPPY_EXTERN NSString *HippyBridgeModuleNameForClass(Class bridgeModuleClass);
* @discussion Context name will be shown on safari development menu.
* only for JSC engine
*/
@property(nonatomic, copy)NSString *contextName;
@property (nonatomic, copy) NSString *contextName;

/**
* Set module name
Expand Down
8 changes: 6 additions & 2 deletions framework/ios/base/executors/HippyJSExecutor.mm
Original file line number Diff line number Diff line change
Expand Up @@ -363,10 +363,14 @@ - (void)setContextName:(NSString *)contextName {
if (!contextName) {
return;
}
WeakCtxPtr weak_ctx = self.pScope->GetContext();
__weak __typeof(self)weakSelf = self;
[self executeBlockOnJavaScriptQueue:^{
@autoreleasepool {
SharedCtxPtr context = weak_ctx.lock();
__strong __typeof(weakSelf)strongSelf = weakSelf;
if (!strongSelf.pScope) {
return;
}
SharedCtxPtr context = strongSelf.pScope->GetContext();
if (!context) {
return;
}
Expand Down
2 changes: 1 addition & 1 deletion framework/ios/debug/devtools/HippyDevInfo.m
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ - (void)parseWsURLWithURLQuery:(NSString *)query {
_wsURL = [debugWsURL substringFromIndex:range.location + range.length];
}

- (NSString *)assembleFullWSURLWithClientId:(NSString *)clientId contextName:(NSString *) contextName{
- (NSString *)assembleFullWSURLWithClientId:(NSString *)clientId contextName:(NSString *)contextName {
if (self.port.length <= 0) {
self.port = [self.scheme isEqualToString:HippyDevWebSocketSchemeWs] ? @"80" : @"443";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@
#include "jni/jni_env.h"
#include "renderer/native_render_manager.h"

#ifdef ENABLE_INSPECTOR
#include "devtools/devtools_utils.h"
#endif

using DomArgument = hippy::dom::DomArgument;
using DomEvent = hippy::dom::DomEvent;
Expand Down Expand Up @@ -291,6 +294,12 @@ void DoCallBack(JNIEnv *j_env, jobject j_object,

callback(std::make_shared<DomArgument>(*params));
}};
#ifdef ENABLE_INSPECTOR
if (hippy::devtools::DevToolsUtil::ShouldAvoidPostDomManagerTask(func_name)) {
ops[0]();
return;
}
#endif
dom_manager->PostTask(Scene(std::move(ops)));
}

Expand Down
Loading

0 comments on commit c29e34a

Please sign in to comment.