Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ We need a entry-point to start the application, and we use ArkTS to manage the a
}
```

5. Change the `moduleName` to your rust project name. For example, we need to change it with `hello` in this project.
5. Set `moduleName` to the bare module name, for example `hello`. The framework will load `libhello.so` internally. You can also pass `string[]` when one ability needs to initialize multiple native modules.

6. Build your rust project and copy the dynamic library to (Open-)Harmony(Next) project.

Expand Down
4 changes: 4 additions & 0 deletions crates/ability/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@

openharmony-ability is a crate for the OpenHarmony/HarmonyNext ability. It provides a way to create an OpenHarmony/HarmonyNext application with rust.

## Runtime Context

`RustAbility` passes the ArkTS init context into Rust during `init(context)`. In Rust, `OpenHarmonyApp` can read `moduleName`, `basePath`, `prefPath`, and `preferredLocales` via `init_context()`, `module_name()`, `base_path()`, `pref_path()`, and `preferred_locales()`.

## License

This project is licensed under the [MIT license](https://github.com/harmony-contrib/openharmony-ability/blob/main/LICENSE)
45 changes: 45 additions & 0 deletions crates/ability/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use std::{
};

use futures_channel::oneshot;
use napi_derive_ohos::napi;
use napi_ohos::{
bindgen_prelude::{CallbackContext, Function, JsObjectValue, Object, Unknown},
threadsafe_function::ThreadsafeFunctionCallMode,
Expand Down Expand Up @@ -65,6 +66,15 @@ fn parse_avoid_area_options(options: Object<'_>) -> Option<(AvoidAreaType, Avoid
Some((area_type, avoid_area))
}

#[napi(object)]
#[derive(Clone, Debug, Default)]
pub struct AbilityInitContext {
pub base_path: Option<String>,
pub pref_path: Option<String>,
pub preferred_locales: Option<String>,
pub module_name: Option<String>,
}

#[derive(Clone)]
pub struct OpenHarmonyAppInner {
pub(crate) raw_window: Option<RawWindow>,
Expand All @@ -77,6 +87,7 @@ pub struct OpenHarmonyAppInner {
pub(crate) rect: Rect,
pub(crate) window_rect: Rect,
pub(crate) avoid_areas: HashMap<AvoidAreaType, AvoidArea>,
pub(crate) init_context: AbilityInitContext,
}

impl PartialEq for OpenHarmonyAppInner {
Expand Down Expand Up @@ -132,6 +143,7 @@ impl OpenHarmonyAppInner {
rect: Default::default(),
window_rect: Default::default(),
avoid_areas: HashMap::new(),
init_context: AbilityInitContext::default(),
}
}

Expand Down Expand Up @@ -191,6 +203,14 @@ impl OpenHarmonyAppInner {
default_display_scaled_density()
}

pub fn init_context(&self) -> AbilityInitContext {
self.init_context.clone()
}

pub fn set_init_context(&mut self, context: AbilityInitContext) {
self.init_context = context;
}

pub fn exit(&self, code: i32) -> Result<()> {
let ret = unsafe { get_helper() };
if let Some(h) = ret.borrow().as_ref() {
Expand Down Expand Up @@ -287,6 +307,31 @@ impl OpenHarmonyApp {
.set_frame_rate(min, max, expected);
}

#[doc(hidden)]
pub fn set_init_context(&self, context: AbilityInitContext) {
self.inner.write().unwrap().set_init_context(context);
}

pub fn init_context(&self) -> AbilityInitContext {
self.inner.read().unwrap().init_context()
}

pub fn module_name(&self) -> Option<String> {
self.init_context().module_name
}

pub fn base_path(&self) -> Option<String> {
self.init_context().base_path
}

pub fn pref_path(&self) -> Option<String> {
self.init_context().pref_path
}

pub fn preferred_locales(&self) -> Option<String> {
self.init_context().preferred_locales
}

pub fn show_keyboard(&self) {
let _guard = self
.is_keyboard_show
Expand Down
4 changes: 4 additions & 0 deletions crates/derive/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ fn openharmony_app(app: OpenHarmonyApp) {
}
```

### Init Context

The generated `init(context)` now forwards ArkTS init data into Rust. Inside your `OpenHarmonyApp`, you can read it through `app.init_context()`, `app.module_name()`, `app.base_path()`, `app.pref_path()`, and `app.preferred_locales()`.

### webview

Using `ArkWeb` to render everything.
Expand Down
17 changes: 3 additions & 14 deletions crates/derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,24 +29,18 @@ fn parse_ability_args(attr: TokenStream) -> syn::Result<AbilityArgs> {
return Ok(args);
}

// Parse attribute arguments as a list of Meta items
// Convert proc_macro::TokenStream to proc_macro2::TokenStream for parsing
let attr_stream = proc_macro2::TokenStream::from(attr);
let meta_list = syn::parse2::<MetaList>(attr_stream)?;

// Iterate over the meta items
for meta in meta_list.metas {
match meta {
Meta::Path(path) => {
// Handle named flags like `webview`
if path.is_ident("webview") {
args.webview = true;
}
}
Meta::NameValue(MetaNameValue { path, value, .. }) => {
// Handle key-value pairs like `protocol = "value"`
if path.is_ident("protocol") {
// Parse the value as an expression and extract string literal
if let syn::Expr::Lit(syn::ExprLit {
lit: syn::Lit::Str(lit_str),
..
Expand All @@ -61,10 +55,7 @@ fn parse_ability_args(attr: TokenStream) -> syn::Result<AbilityArgs> {
}
}
}
Meta::List(_) => {
// Handle nested list-style attributes if needed
// For now, we'll skip them
}
Meta::List(_) => {}
}
}

Expand Down Expand Up @@ -120,7 +111,6 @@ pub fn ability(attr: TokenStream, item: TokenStream) -> TokenStream {
}
};

// Register custom protocol if protocol is specified and webview is enabled
let protocol_registrations_apply = if args.protocol.is_some() && args.webview {
quote::quote! {
#[napi_derive_ohos::napi]
Expand Down Expand Up @@ -153,9 +143,6 @@ pub fn ability(attr: TokenStream, item: TokenStream) -> TokenStream {

#protocol_registrations_apply

/// Get back press interceptor result
/// Can be called from ArkTS page lifecycle (onBackPress)
/// Returns true to intercept back press, false to pass through
#[napi_derive_ohos::napi]
pub fn on_back_press_intercept() -> bool {
(*APP).get_back_press_interceptor()
Expand All @@ -164,7 +151,9 @@ pub fn ability(attr: TokenStream, item: TokenStream) -> TokenStream {
#[napi_derive_ohos::napi]
pub fn init<'a>(
env: &'a napi_ohos::Env,
context: Option<openharmony_ability::AbilityInitContext>,
) -> napi_ohos::Result<openharmony_ability::ApplicationLifecycle<'a>> {
(*APP).set_init_context(context.unwrap_or_default());
let lifecycle_handle = openharmony_ability::create_lifecycle_handle(env, (*APP).clone())?;
#fn_name((*APP).clone());
Ok(lifecycle_handle)
Expand Down
4 changes: 2 additions & 2 deletions package/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ Here are some notes and tips:

1. For every lifecycle callback, you must call the super method to forward the event to rust code as first and then write your own logic.

2. `moduleName` is the name of your native module name which file name is `lib${moduleName}.so`. **You must define it in your project**.
2. `moduleName` is the bare native module name, such as `hello`. The framework resolves it to `libhello.so` internally. You must define it in your project.

### loadMode

Expand Down Expand Up @@ -127,7 +127,7 @@ struct Index {
Column() {
SegmentButton({ options: this.tabOptions, selectedIndexes: $tabSelectedIndexes })
// Must use the default component to render the UI
DefaultXComponent()
DefaultXComponent({ moduleName: "example" })
}
.width('100%')
}
Expand Down
2 changes: 1 addition & 1 deletion rust_ability/ability_rust/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ We need a entry-point to start the application, and we use ArkTS to manage the a
}
```

5. Change the `moduleName` to your rust project name. For example, we need to change it with `hello` in this project.
5. Set `moduleName` to the bare module name, for example `hello`. The framework will load `libhello.so` internally. You can also pass `string[]` when one ability needs to initialize multiple native modules.

6. Build your rust project and copy the dynamic library to (Open-)Harmony(Next) project.

Expand Down
2 changes: 1 addition & 1 deletion rust_ability/ability_rust/oh-package-lock.json5

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading