diff --git a/frameworks/native/ability/native/ui_extension_ability/js_ui_extension_base.cpp b/frameworks/native/ability/native/ui_extension_ability/js_ui_extension_base.cpp index 120f24263af446febeacc42ef0e643674d41ca74..ab83b5a41762aff2de9d08919df7b3a21c1942e0 100644 --- a/frameworks/native/ability/native/ui_extension_ability/js_ui_extension_base.cpp +++ b/frameworks/native/ability/native/ui_extension_ability/js_ui_extension_base.cpp @@ -141,7 +141,6 @@ std::shared_ptr JsUIExtensionBase::Init(const std::shared_ptrmoduleName); moduleName.append("::").append(abilityInfo_->name); HandleScope handleScope(jsRuntime_); - napi_env env = jsRuntime_.GetNapiEnv(); jsObj_ = jsRuntime_.LoadModule( moduleName, srcPath, abilityInfo_->hapPath, abilityInfo_->compileMode == CompileMode::ES_MODULE); @@ -150,25 +149,26 @@ std::shared_ptr JsUIExtensionBase::Init(const std::shared_ptrGetNapiValue(); - if (!CheckTypeForNapiValue(env, obj, napi_object)) { - TAG_LOGE(AAFwkTag::UI_EXT, "obj is not object"); - return nullptr; - } - - BindContext(env, obj); + BindContext(); return JsExtensionCommon::Create(jsRuntime_, static_cast(*jsObj_), shellContextRef_); } -void JsUIExtensionBase::BindContext(napi_env env, napi_value obj) +void JsUIExtensionBase::BindContext() { - if (context_ == nullptr) { - TAG_LOGE(AAFwkTag::UI_EXT, "context_ is nullptr"); + HandleScope handleScope(jsRuntime_); + if (jsObj_ == nullptr) { + TAG_LOGE(AAFwkTag::UI_EXT, "jsObj_ is nullptr"); + return; + } + napi_env env = jsRuntime_.GetNapiEnv(); + napi_value obj = jsObj_->GetNapiValue(); + if (!CheckTypeForNapiValue(env, obj, napi_object)) { + TAG_LOGE(AAFwkTag::UI_EXT, "obj is not object"); return; } - if (obj == nullptr) { - TAG_LOGE(AAFwkTag::UI_EXT, "obj is nullptr"); + if (context_ == nullptr) { + TAG_LOGE(AAFwkTag::UI_EXT, "context_ is nullptr"); return; } TAG_LOGD(AAFwkTag::UI_EXT, "BindContext CreateJsUIExtensionContext."); diff --git a/interfaces/kits/native/ability/native/ui_extension_ability/js_ui_extension_base.h b/interfaces/kits/native/ability/native/ui_extension_ability/js_ui_extension_base.h index b7a59997d9f2d701f9f68b27f11df356fd7fe202..053a52a5f32eb437ad7248dfab65f5ebc059bbe6 100644 --- a/interfaces/kits/native/ability/native/ui_extension_ability/js_ui_extension_base.h +++ b/interfaces/kits/native/ability/native/ui_extension_ability/js_ui_extension_base.h @@ -151,8 +151,8 @@ public: */ void SetContext(const std::shared_ptr &context) override; -private: - void BindContext(napi_env env, napi_value obj); + void BindContext() override; +protected: napi_value CallObjectMethod(const char *name, napi_value const *argv = nullptr, size_t argc = 0); void ForegroundWindow(const AAFwk::Want &want, const sptr &sessionInfo); void BackgroundWindow(const sptr &sessionInfo); @@ -168,15 +168,16 @@ private: void PostInsightIntentExecuted(const sptr &sessionInfo, const AppExecFwk::InsightIntentExecuteResult &result, bool needForeground); +protected: JsRuntime &jsRuntime_; - std::unique_ptr jsObj_; std::shared_ptr shellContextRef_; + std::unique_ptr jsObj_; + std::shared_ptr context_; std::map> uiWindowMap_; std::set foregroundWindows_; std::map> contentSessions_; std::shared_ptr abilityResultListeners_ = nullptr; std::shared_ptr abilityInfo_; - std::shared_ptr context_; sptr token_ = nullptr; }; } // namespace AbilityRuntime diff --git a/interfaces/kits/native/ability/native/ui_extension_ability/js_ui_extension_context.h b/interfaces/kits/native/ability/native/ui_extension_ability/js_ui_extension_context.h index bc8617201e2b183ba03ebcef06a140349fb0d3ad..a541015e50835518ba588c3833f8a353f4c0f8a9 100755 --- a/interfaces/kits/native/ability/native/ui_extension_ability/js_ui_extension_context.h +++ b/interfaces/kits/native/ability/native/ui_extension_ability/js_ui_extension_context.h @@ -55,8 +55,9 @@ protected: virtual napi_value OnReportDrawnCompleted(napi_env env, NapiCallbackInfo& info); virtual napi_value OnOpenAtomicService(napi_env env, NapiCallbackInfo& info); -private: +protected: std::weak_ptr context_; +private: sptr freeInstallObserver_ = nullptr; friend class JsEmbeddableUIAbilityContext; diff --git a/interfaces/kits/native/ability/native/ui_extension_ability/ui_extension_base_impl.h b/interfaces/kits/native/ability/native/ui_extension_ability/ui_extension_base_impl.h index 3a24798167d61bc6e0103d71d320fe0d09f02fc4..15d606939b9cfccdd0cb402e49fa416337053a7b 100644 --- a/interfaces/kits/native/ability/native/ui_extension_ability/ui_extension_base_impl.h +++ b/interfaces/kits/native/ability/native/ui_extension_ability/ui_extension_base_impl.h @@ -57,6 +57,8 @@ public: virtual void SetAbilityInfo(const std::shared_ptr &abilityInfo) = 0; virtual void SetContext(const std::shared_ptr &context) = 0; + + virtual void BindContext() = 0; }; } // namespace AbilityRuntime } // namespace OHOS diff --git a/test/sample/demo_ui_extension/js/napi/demo_ui_extension_ability/demo_ui_extension_ability.js b/test/sample/demo_ui_extension/js/napi/demo_ui_extension_ability/demo_ui_extension_ability.js index 04bccd8ed5671b74be1508a1aad02fa84b4437c0..779157baeed50b1a0c5e6f59d6e853652ad43c8f 100644 --- a/test/sample/demo_ui_extension/js/napi/demo_ui_extension_ability/demo_ui_extension_ability.js +++ b/test/sample/demo_ui_extension/js/napi/demo_ui_extension_ability/demo_ui_extension_ability.js @@ -16,6 +16,9 @@ let UIExtensionAbility = requireNapi('app.ability.UIExtensionAbility'); class DemoUIExtensionAbility extends UIExtensionAbility { + onTest(){ + console.log('DemoUIExtensionAbility onTest'); + } } export default DemoUIExtensionAbility; diff --git a/test/sample/demo_ui_extension/native/demo_ui_extension_ability/BUILD.gn b/test/sample/demo_ui_extension/native/demo_ui_extension_ability/BUILD.gn index 3db9b188e273a174e2d60b59deaefaf912ea30fa..434bb7e8233c650308785ae7c2c60dac34ded5f3 100644 --- a/test/sample/demo_ui_extension/native/demo_ui_extension_ability/BUILD.gn +++ b/test/sample/demo_ui_extension/native/demo_ui_extension_ability/BUILD.gn @@ -38,6 +38,7 @@ ohos_shared_library("demo_ui_extension") { sources = [ "src/demo_ui_extension.cpp", "src/js_demo_ui_extension.cpp", + "src/js_demo_ui_extension_context.cpp", ] # If not in ability_runtime repo, use external_deps diff --git a/test/sample/demo_ui_extension/native/demo_ui_extension_ability/include/js_demo_ui_extension.h b/test/sample/demo_ui_extension/native/demo_ui_extension_ability/include/js_demo_ui_extension.h index 1fab78af8e6e07a7f3060b1f42583b39e3125392..d448ce994369b050e01a39c88c7ee273a0a0cebd 100644 --- a/test/sample/demo_ui_extension/native/demo_ui_extension_ability/include/js_demo_ui_extension.h +++ b/test/sample/demo_ui_extension/native/demo_ui_extension_ability/include/js_demo_ui_extension.h @@ -17,11 +17,13 @@ #define OHOS_ABILITY_RUNTIME_JS_DEMO_UI_EXTENSION_H #include "demo_ui_extension.h" +#include "js_ui_extension_base.h" #include "runtime.h" namespace OHOS { namespace AbilityRuntime { class JsDemoUIExtension : public DemoUIExtension, + public JsUIExtensionBase, public std::enable_shared_from_this { public: explicit JsDemoUIExtension(const std::unique_ptr &runtime); @@ -34,6 +36,10 @@ public: * @return The JsDemoUIExtension instance. */ static JsDemoUIExtension *Create(const std::unique_ptr &runtime); + + void OnForeground(const Want &want, sptr sessionInfo) override; + + void BindContext() override; }; } // namespace AbilityRuntime } // namespace OHOS diff --git a/test/sample/demo_ui_extension/native/demo_ui_extension_ability/include/js_demo_ui_extension_context.h b/test/sample/demo_ui_extension/native/demo_ui_extension_ability/include/js_demo_ui_extension_context.h new file mode 100644 index 0000000000000000000000000000000000000000..1e03328e237e2a41d476fd4f3e6611d1e9b2bd44 --- /dev/null +++ b/test/sample/demo_ui_extension/native/demo_ui_extension_ability/include/js_demo_ui_extension_context.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed 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. + */ + +#ifndef OHOS_ABILITY_RUNTIME_JS_DEMO_UI_EXTENSION_CONTEXT_H +#define OHOS_ABILITY_RUNTIME_JS_DEMO_UI_EXTENSION_CONTEXT_H + +#include + +#include "ui_extension_context.h" +#include "js_free_install_observer.h" +#include "native_engine/native_engine.h" +#include "js_ui_extension_context.h" + +namespace OHOS { +namespace AbilityRuntime { +struct NapiCallbackInfo; + +class JsDemoUIExtensionContext : public JsUIExtensionContext { +public: + explicit JsDemoUIExtensionContext(const std::shared_ptr& context) + : JsUIExtensionContext(context) {} + virtual ~JsDemoUIExtensionContext() = default; + static void Finalizer(napi_env env, void* data, void* hint); + static napi_value TestMethod(napi_env env, napi_callback_info info); + static napi_value CreateJsDemoUIExtensionContext(napi_env env, std::shared_ptr context); + +protected: + virtual napi_value OnTestMethod(napi_env env, NapiCallbackInfo& info); +}; + +} // namespace AbilityRuntime +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_JS_DEMO_UI_EXTENSION_CONTEXT_H \ No newline at end of file diff --git a/test/sample/demo_ui_extension/native/demo_ui_extension_ability/src/js_demo_ui_extension.cpp b/test/sample/demo_ui_extension/native/demo_ui_extension_ability/src/js_demo_ui_extension.cpp index fc0f671291a1c5d712728e02f5e9ad0d241c1d9a..b762e34f7a4124d062614108775b47ad11cebdbf 100644 --- a/test/sample/demo_ui_extension/native/demo_ui_extension_ability/src/js_demo_ui_extension.cpp +++ b/test/sample/demo_ui_extension/native/demo_ui_extension_ability/src/js_demo_ui_extension.cpp @@ -17,25 +17,138 @@ #include "hilog_wrapper.h" #include "js_ui_extension_base.h" +#include "js_demo_ui_extension_context.h" namespace OHOS { namespace AbilityRuntime { +namespace { +constexpr size_t ARGC_ONE = 1; +} // namespace JsDemoUIExtension *JsDemoUIExtension::Create(const std::unique_ptr &runtime) { TAG_LOGD(AAFwkTag::TEST, "Create js demo uiextension."); return new JsDemoUIExtension(runtime); } -JsDemoUIExtension::JsDemoUIExtension(const std::unique_ptr &runtime) +JsDemoUIExtension::JsDemoUIExtension(const std::unique_ptr &runtime) : JsUIExtensionBase(runtime) { - TAG_LOGD(AAFwkTag::TEST, "Js demo uiextension constructor."); - auto uiExtensionBaseImpl = std::make_unique(runtime); - SetUIExtensionBaseImpl(std::move(uiExtensionBaseImpl)); + SetUIExtensionBaseImpl(std::shared_ptr(this)); } JsDemoUIExtension::~JsDemoUIExtension() { TAG_LOGD(AAFwkTag::TEST, "Js demo uiextension destructor."); } + +void JsDemoUIExtension::OnForeground(const Want &want, sptr sessionInfo) +{ + TAG_LOGE(AAFwkTag::UI_EXT, "OnForeground"); + + ForegroundWindow(want, sessionInfo); + HandleScope handleScope(jsRuntime_); + CallObjectMethod("onForeground"); + CallObjectMethod("onTest"); +} + +napi_value AttachUIExtensionBaseContext(napi_env env, void *value, void*) +{ + TAG_LOGD(AAFwkTag::UI_EXT, "called"); + if (value == nullptr) { + TAG_LOGE(AAFwkTag::UI_EXT, "invalid parameter."); + return nullptr; + } + + auto ptr = reinterpret_cast*>(value)->lock(); + if (ptr == nullptr) { + TAG_LOGE(AAFwkTag::UI_EXT, "invalid context."); + return nullptr; + } + napi_value object = JsDemoUIExtensionContext::CreateJsDemoUIExtensionContext(env, ptr); + if (object == nullptr) { + TAG_LOGE(AAFwkTag::UI_EXT, "create context error."); + return nullptr; + } + auto contextRef = JsRuntime::LoadSystemModuleByEngine( + env, "application.UIExtensionContext", &object, 1); + if (contextRef == nullptr) { + TAG_LOGD(AAFwkTag::UI_EXT, "Failed to get LoadSystemModuleByEngine"); + return nullptr; + } + auto contextObj = contextRef->GetNapiValue(); + if (contextObj == nullptr) { + TAG_LOGE(AAFwkTag::UI_EXT, "load context error."); + return nullptr; + } + if (!CheckTypeForNapiValue(env, contextObj, napi_object)) { + TAG_LOGE(AAFwkTag::UI_EXT, "not object."); + return nullptr; + } + napi_coerce_to_native_binding_object( + env, contextObj, DetachCallbackFunc, AttachUIExtensionBaseContext, value, nullptr); + auto workContext = new (std::nothrow) std::weak_ptr(ptr); + napi_wrap(env, contextObj, workContext, + [](napi_env, void *data, void*) { + TAG_LOGD(AAFwkTag::UI_EXT, "Finalizer for weak_ptr ui extension context is called"); + if (data == nullptr) { + TAG_LOGE(AAFwkTag::UI_EXT, "Finalizer for weak_ptr is nullptr"); + return; + } + delete static_cast*>(data); + }, + nullptr, nullptr); + return contextObj; +} + +void JsDemoUIExtension::BindContext() +{ + HandleScope handleScope(jsRuntime_); + std::shared_ptr context = JsUIExtensionBase::context_; + if (jsObj_ == nullptr) { + TAG_LOGE(AAFwkTag::UI_EXT, "jsObj_ is nullptr"); + return; + } + napi_env env = jsRuntime_.GetNapiEnv(); + napi_value obj = jsObj_->GetNapiValue(); + if (!CheckTypeForNapiValue(env, obj, napi_object)) { + TAG_LOGE(AAFwkTag::UI_EXT, "obj is not object"); + return; + } + if (context == nullptr) { + TAG_LOGE(AAFwkTag::UI_EXT, "context is nullptr"); + return; + } + TAG_LOGD(AAFwkTag::UI_EXT, "BindContext CreateJsDemoUIExtensionContext."); + napi_value contextObj = JsDemoUIExtensionContext::CreateJsDemoUIExtensionContext(env, context); + if (contextObj == nullptr) { + TAG_LOGE(AAFwkTag::UI_EXT, "Create js ui extension context error."); + return; + } + shellContextRef_ = JsRuntime::LoadSystemModuleByEngine( + env, "application.UIExtensionContext", &contextObj, ARGC_ONE); + if (shellContextRef_ == nullptr) { + TAG_LOGD(AAFwkTag::UI_EXT, "Failed to get LoadSystemModuleByEngine"); + return; + } + contextObj = shellContextRef_->GetNapiValue(); + if (!CheckTypeForNapiValue(env, contextObj, napi_object)) { + TAG_LOGE(AAFwkTag::UI_EXT, "Failed to get context native object"); + return; + } + auto workContext = new (std::nothrow) std::weak_ptr(context); + napi_coerce_to_native_binding_object( + env, contextObj, DetachCallbackFunc, AttachUIExtensionBaseContext, workContext, nullptr); + context->Bind(jsRuntime_, shellContextRef_.get()); + napi_set_named_property(env, obj, "context", contextObj); + napi_wrap(env, contextObj, workContext, + [](napi_env, void *data, void*) { + TAG_LOGD(AAFwkTag::UI_EXT, "Finalizer for weak_ptr ui extension context is called"); + if (data == nullptr) { + TAG_LOGE(AAFwkTag::UI_EXT, "Finalizer for weak_ptr is nullptr"); + return; + } + delete static_cast*>(data); + }, + nullptr, nullptr); +} } // namespace AbilityRuntime } // namespace OHOS diff --git a/test/sample/demo_ui_extension/native/demo_ui_extension_ability/src/js_demo_ui_extension_context.cpp b/test/sample/demo_ui_extension/native/demo_ui_extension_ability/src/js_demo_ui_extension_context.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b162fcfc53311aba62a9dea850e7b04e63b220a4 --- /dev/null +++ b/test/sample/demo_ui_extension/native/demo_ui_extension_ability/src/js_demo_ui_extension_context.cpp @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed 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. + */ + +#include "js_ui_extension_context.h" + +#include + +#include "ability_manager_client.h" +#include "event_handler.h" +#include "hilog_tag_wrapper.h" +#include "hilog_wrapper.h" +#include "js_extension_context.h" +#include "js_error_utils.h" +#include "js_data_struct_converter.h" +#include "js_demo_ui_extension_context.h" +#include "js_runtime.h" +#include "js_runtime_utils.h" +#include "napi/native_api.h" +#include "napi_common_ability.h" +#include "napi_common_want.h" +#include "napi_common_util.h" +#include "napi_common_start_options.h" +#include "napi_remote_object.h" +#include "open_link_options.h" +#include "open_link/napi_common_open_link_options.h" +#include "start_options.h" +#include "hitrace_meter.h" +#include "uri.h" + +namespace OHOS { +namespace AbilityRuntime { +namespace { +constexpr int32_t INDEX_ZERO = 0; +} // namespace + +void JsDemoUIExtensionContext::Finalizer(napi_env env, void* data, void* hint) +{ + TAG_LOGD(AAFwkTag::UI_EXT, "JsDemoUIExtensionContext Finalizer is called"); + std::unique_ptr(static_cast(data)); +} + +napi_value JsDemoUIExtensionContext::TestMethod(napi_env env, napi_callback_info info) +{ + GET_NAPI_INFO_AND_CALL(env, info, JsDemoUIExtensionContext, OnTestMethod); +} + +napi_value JsDemoUIExtensionContext::OnTestMethod(napi_env env, NapiCallbackInfo& info) +{ + TAG_LOGD(AAFwkTag::UI_EXT, "called."); + auto innerErrorCode = std::make_shared(ERR_OK); + NapiAsyncTask::ExecuteCallback execute = [weak = context_, innerErrorCode]() { + auto context = weak.lock(); + if (!context) { + TAG_LOGW(AAFwkTag::UI_EXT, "context is released"); + *innerErrorCode = static_cast(AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT); + return; + } + }; + + NapiAsyncTask::CompleteCallback complete = [innerErrorCode](napi_env env, NapiAsyncTask& task, int32_t status) { + if (*innerErrorCode == ERR_OK) { + task.Resolve(env, CreateJsUndefined(env)); + } else { + task.Reject(env, CreateJsErrorByNativeErr(env, *innerErrorCode)); + } + }; + + napi_value lastParam = info.argv[INDEX_ZERO]; + napi_value result = nullptr; + NapiAsyncTask::ScheduleHighQos("JsDemoUIExtensionContext::OnTestMethod", + env, CreateAsyncTaskWithLastParam(env, lastParam, std::move(execute), std::move(complete), &result)); + return result; +} + +napi_value JsDemoUIExtensionContext::CreateJsDemoUIExtensionContext(napi_env env, + std::shared_ptr context) +{ + std::shared_ptr abilityInfo = nullptr; + if (context) { + abilityInfo = context->GetAbilityInfo(); + } + napi_value objValue = CreateJsExtensionContext(env, context, abilityInfo); + + std::unique_ptr jsContext = std::make_unique(context); + napi_wrap(env, objValue, jsContext.release(), Finalizer, nullptr, nullptr); + + const char *moduleName = "JsDemoUIExtensionContext"; + BindNativeFunction(env, objValue, "startAbility", moduleName, StartAbility); + BindNativeFunction(env, objValue, "openLink", moduleName, OpenLink); + BindNativeFunction(env, objValue, "terminateSelf", moduleName, TerminateSelf); + BindNativeFunction(env, objValue, "startAbilityForResult", moduleName, StartAbilityForResult); + BindNativeFunction(env, objValue, "terminateSelfWithResult", moduleName, TerminateSelfWithResult); + BindNativeFunction(env, objValue, "startAbilityForResultAsCaller", moduleName, StartAbilityForResultAsCaller); + BindNativeFunction(env, objValue, "connectServiceExtensionAbility", moduleName, ConnectAbility); + BindNativeFunction(env, objValue, "disconnectServiceExtensionAbility", moduleName, DisconnectAbility); + BindNativeFunction(env, objValue, "reportDrawnCompleted", moduleName, ReportDrawnCompleted); + BindNativeFunction(env, objValue, "openAtomicService", moduleName, OpenAtomicService); + BindNativeFunction(env, objValue, "testMethod", moduleName, TestMethod); + + return objValue; +} +} // namespace AbilityRuntime +} // namespace OHOS \ No newline at end of file