openharmony_ability_derive/
lib.rs1use darling::FromMeta;
2use proc_macro::TokenStream;
3use syn::ItemFn;
4
5#[derive(FromMeta, Default, Debug)]
6struct AbilityArgs {
7 #[darling(default)]
8 webview: bool,
9 #[darling(default)]
10 protocol: Option<String>,
11}
12
13#[proc_macro_attribute]
14pub fn ability(attr: TokenStream, item: TokenStream) -> TokenStream {
15 let ast = syn::parse_macro_input!(item as ItemFn);
16 let fn_name = &ast.sig.ident;
17 let block = &ast.block;
18 let arg = &ast.sig.inputs;
19
20 let args = if attr.is_empty() {
21 AbilityArgs::default()
22 } else {
23 match darling::ast::NestedMeta::parse_meta_list(proc_macro2::TokenStream::from(attr)) {
24 Ok(list) => match AbilityArgs::from_list(&list) {
25 Ok(args) => args,
26 Err(e) => {
27 return TokenStream::from(e.write_errors());
28 }
29 },
30 Err(e) => {
31 return TokenStream::from(e.to_compile_error());
32 }
33 }
34 };
35
36 let protocol_registrations = args
37 .protocol
38 .as_ref()
39 .map(|protocols| {
40 protocols
41 .split(",")
42 .map(|protocol| {
43 let protocol_lit = syn::LitStr::new(protocol, proc_macro2::Span::call_site());
44 quote::quote! {
45 openharmony_ability::native_web::CustomProtocol::add_protocol_with_option(#protocol_lit,
46 openharmony_ability::native_web::CustomProtocolOption::Standard |
47 openharmony_ability::native_web::CustomProtocolOption::CorsEnabled |
48 openharmony_ability::native_web::CustomProtocolOption::CspBypassing |
49 openharmony_ability::native_web::CustomProtocolOption::FetchEnabled |
50 openharmony_ability::native_web::CustomProtocolOption::CodeCacheEnabled
51 );
52 }
53 })
54 .collect::<Vec<_>>()
55 })
56 .unwrap_or_default();
57
58 let render = if args.webview {
59 quote::quote! {
60 #[openharmony_ability::napi_derive::napi]
61 pub fn webview_render<'a>(
62 env: &'a openharmony_ability::napi::Env,
63 helper: openharmony_ability::napi::bindgen_prelude::ObjectRef,
64 ) -> openharmony_ability::napi::Result<openharmony_ability::WebViewComponentEventCallback<'a>> {
65 let callback = openharmony_ability::render(env, helper, (*APP).clone())?;
66 Ok(callback)
67 }
68 }
69 } else {
70 quote::quote! {
71 #[openharmony_ability::napi_derive::napi]
72 pub fn render<'a>(
73 env: &'a openharmony_ability::napi::Env,
74 helper: openharmony_ability::napi::bindgen_prelude::ObjectRef,
75 slot: openharmony_ability::arkui::ArkUIHandle,
76 ) -> openharmony_ability::napi::Result<()> {
77 let root = openharmony_ability::render(env, helper, slot, (*APP).clone())?;
78 ROOT_NODE.replace(Some(root));
79 Ok(())
80 }
81 }
82 };
83
84 let protocol_registrations_apply = if args.protocol.is_some() && args.webview {
86 quote::quote! {
87 #[openharmony_ability::napi_derive::napi]
88 pub fn register_custom_protocol<'a>(
89 env: &'a openharmony_ability::napi::Env,
90 ) -> openharmony_ability::napi::Result<()> {
91 #(#protocol_registrations)*
92
93 openharmony_ability::native_web::CustomProtocol::register();
94
95 Ok(())
96 }
97 }
98 } else {
99 quote::quote! {}
100 };
101
102 let f = quote::quote! {
103 pub(crate) fn #fn_name(#arg) #block
104
105 mod openharmony_ability_mod {
106 use super::*;
107 use openharmony_ability::napi as napi_ohos;
108
109 static APP: std::sync::LazyLock<openharmony_ability::OpenHarmonyApp> =
110 std::sync::LazyLock::new(|| openharmony_ability::OpenHarmonyApp::new());
111
112 thread_local! {
113 pub static ROOT_NODE: std::cell::RefCell<Option<openharmony_ability::arkui::RootNode>> = std::cell::RefCell::new(None);
114 }
115
116 #protocol_registrations_apply
117
118 #[openharmony_ability::napi_derive::napi]
119 pub fn init<'a>(
120 env: &'a openharmony_ability::napi::Env,
121 ) -> openharmony_ability::napi::Result<openharmony_ability::ApplicationLifecycle<'a>> {
122 let lifecycle_handle = openharmony_ability::create_lifecycle_handle(env, (*APP).clone())?;
123 #fn_name((*APP).clone());
124 Ok(lifecycle_handle)
125 }
126
127 #render
128 }
129 };
130
131 f.into()
132}