Skip to content

Commit dc9ca83

Browse files
committed
Add AndroidApp::vm_as_ptr() and ::activity_as_ptr() APIs
This enables applications to make JNI calls without needing the `ndk-context` crate - which we would like to deprecate. Fixes: #60
1 parent 6942637 commit dc9ca83

File tree

4 files changed

+68
-0
lines changed

4 files changed

+68
-0
lines changed

android-activity/CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
33
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
44

55
## [Unreleased]
6+
### Added
7+
- Added `AndroidApp::vm_as_ptr()` to expose JNI `JavaVM` pointer ([#60](https://github.com/rust-mobile/android-activity/issues/60))
8+
- Added `AndroidApp::activity_as_ptr()` to expose Android `Activity` JNI reference as pointer ([#60](https://github.com/rust-mobile/android-activity/issues/60))
69

710
## [0.4] - 2022-11-10
811
### Changed

android-activity/src/game_activity/mod.rs

+11
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use std::sync::{Arc, RwLock};
1212
use std::time::Duration;
1313
use std::{ptr, thread};
1414

15+
use libc::c_void;
1516
use log::{error, trace, Level};
1617

1718
use jni_sys::*;
@@ -155,6 +156,16 @@ pub struct AndroidAppInner {
155156
}
156157

157158
impl AndroidAppInner {
159+
pub fn vm_as_ptr(&self) -> *mut c_void {
160+
let app_ptr = self.native_app.as_ptr();
161+
unsafe { (*(*app_ptr).activity).vm as _ }
162+
}
163+
164+
pub fn activity_as_ptr(&self) -> *mut c_void {
165+
let app_ptr = self.native_app.as_ptr();
166+
unsafe { (*(*app_ptr).activity).javaGameActivity as _ }
167+
}
168+
158169
pub fn native_window(&self) -> Option<NativeWindow> {
159170
self.native_window.read().unwrap().clone()
160171
}

android-activity/src/lib.rs

+44
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ use std::sync::Arc;
6262
use std::sync::RwLock;
6363
use std::time::Duration;
6464

65+
use libc::c_void;
6566
use ndk::asset::AssetManager;
6667
use ndk::native_window::NativeWindow;
6768

@@ -472,6 +473,49 @@ impl AndroidApp {
472473
self.inner.read().unwrap().native_window()
473474
}
474475

476+
/// Returns a pointer to the Java Virtual Machine, for making JNI calls
477+
///
478+
/// This returns a pointer to the Java Virtual Machine which can be used
479+
/// with the [`jni`] crate (or similar crates) to make JNI calls that bridge
480+
/// between native Rust code and Java/Kotlin code running within the JVM.
481+
///
482+
/// If you use the [`jni`] crate you can wrap this as a [`JavaVM`] via:
483+
/// ```ignore
484+
/// # use jni::JavaVM;
485+
/// # let app: AndroidApp = todo!();
486+
/// let vm = unsafe { JavaVM::from_raw(app.vm_as_ptr()) };
487+
/// ```
488+
///
489+
/// [`jni`]: https://crates.io/crates/jni
490+
/// [`JavaVM`]: https://docs.rs/jni/latest/jni/struct.JavaVM.html
491+
pub fn vm_as_ptr(&self) -> *mut c_void {
492+
self.inner.read().unwrap().vm_as_ptr()
493+
}
494+
495+
/// Returns a JNI object reference for this application's JVM `Activity` as a pointer
496+
///
497+
/// If you use the [`jni`] crate you can wrap this as an object reference via:
498+
/// ```ignore
499+
/// # use jni::objects::JObject;
500+
/// # let app: AndroidApp = todo!();
501+
/// let activity = unsafe { JObject::from_raw(app.activity_as_ptr()) };
502+
/// ```
503+
///
504+
/// # JNI Safety
505+
///
506+
/// Note that the object reference will be a JNI global reference, not a
507+
/// local reference and it should not be deleted. Don't wrap the reference
508+
/// in an [`AutoLocal`] which would try to explicitly delete the reference
509+
/// when dropped. Similarly, don't wrap the reference as a [`GlobalRef`]
510+
/// which would also try to explicitly delete the reference when dropped.
511+
///
512+
/// [`jni`]: https://crates.io/crates/jni
513+
/// [`AutoLocal`]: https://docs.rs/jni/latest/jni/objects/struct.AutoLocal.html
514+
/// [`GlobalRef`]: https://docs.rs/jni/latest/jni/objects/struct.GlobalRef.html
515+
pub fn activity_as_ptr(&self) -> *mut c_void {
516+
self.inner.read().unwrap().activity_as_ptr()
517+
}
518+
475519
/// Polls for any events associated with this [AndroidApp] and processes those events
476520
/// (such as lifecycle events) via the given `callback`.
477521
///

android-activity/src/native_activity/mod.rs

+10
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use std::ptr::NonNull;
55
use std::sync::{Arc, RwLock};
66
use std::time::Duration;
77

8+
use libc::c_void;
89
use log::{error, trace};
910

1011
use ndk_sys::ALooper_wake;
@@ -130,6 +131,15 @@ pub(crate) struct AndroidAppInner {
130131
}
131132

132133
impl AndroidAppInner {
134+
pub(crate) fn vm_as_ptr(&self) -> *mut c_void {
135+
unsafe { (*self.native_activity.activity).vm as _ }
136+
}
137+
138+
pub(crate) fn activity_as_ptr(&self) -> *mut c_void {
139+
// "clazz" is a completely bogus name; this is the _instance_ not class pointer
140+
unsafe { (*self.native_activity.activity).clazz as _ }
141+
}
142+
133143
pub(crate) fn native_activity(&self) -> *const ndk_sys::ANativeActivity {
134144
self.native_activity.activity
135145
}

0 commit comments

Comments
 (0)