Add Iris Android APK tooling

This commit is contained in:
iris committed 2026-09-11 03:44:06 -04:00
1 parent 3246f397b5
commit 37f956707e
20 files changed
+1766 -54

No files matched your search

+85 -2
View File
@@ -2,13 +2,96 @@ extern crate proc_macro;
use proc_macro::TokenStream;
use quote::quote;
use syn::{
Attribute, Block, Error, GenericParam, Generics, Ident, ItemStruct, ItemTrait, Signature,
Token, Type, Visibility,
Attribute, Block, Error, FnArg, GenericParam, Generics, Ident, ItemFn, ItemStruct, ItemTrait,
ReturnType, Signature, Token, Type, Visibility,
parse::{Parse, ParseStream, Result},
parse_macro_input, parse_quote,
spanned::Spanned,
};
/// Marks the factory called when Android creates an Iris view.
///
/// An attribute is necessary here because the Android loader requires one
/// exported `JNI_OnLoad` symbol and `android-view` requires a plain function
/// pointer monomorphized for the returned application state. The generated
/// linker and JNI glue is Android-gated; the annotated function therefore
/// does not need its own `cfg` attribute.
#[proc_macro_attribute]
pub fn app_init(args: TokenStream, item: TokenStream) -> TokenStream {
if !args.is_empty() {
return Error::new(
proc_macro2::Span::call_site(),
"app_init takes no arguments",
)
.into_compile_error()
.into();
}
let function = parse_macro_input!(item as ItemFn);
let name = &function.sig.ident;
let ReturnType::Type(_, state) = &function.sig.output else {
return Error::new(
function.sig.output.span(),
"an app_init function must return its application state",
)
.into_compile_error()
.into();
};
if function.sig.inputs.len() != 2
|| function
.sig
.inputs
.iter()
.any(|argument| !matches!(argument, FnArg::Typed(_)))
{
return Error::new(
function.sig.inputs.span(),
"an app_init function takes AndroidUiState and &mut State::Resources",
)
.into_compile_error()
.into();
}
if function.sig.asyncness.is_some()
|| function.sig.constness.is_some()
|| matches!(function.sig.safety, syn::Safety::Unsafe(_))
|| !function.sig.generics.params.is_empty()
{
return Error::new(
function.sig.span(),
"an app_init function must be a plain, non-generic synchronous function",
)
.into_compile_error()
.into();
}
quote! {
#[cfg(target_os = "android")]
#function
#[cfg(target_os = "android")]
mod __iris_android_app {
use super::*;
extern "system" fn new_view_peer<'local>(
env: ::iris::android::__private::JNIEnv<'local>,
view: ::iris::android::__private::View<'local>,
context: ::iris::android::__private::Context<'local>,
) -> ::iris::android::__private::JLong {
::iris::android::new_peer::<#state>(env, view, context, super::#name)
}
#[unsafe(no_mangle)]
pub unsafe extern "system" fn JNI_OnLoad(
vm: *mut ::iris::android::__private::RawJavaVM,
_: *mut ::core::ffi::c_void,
) -> ::iris::android::__private::JInt {
unsafe { ::iris::android::__private::on_load(vm, new_view_peer) }
}
}
}
.into()
}
struct Input {
attrs: Vec<Attribute>,
vis: Visibility,