Skip to content

Commit 114a1e8

Browse files
committed
Add NativeActivity
1 parent b2965dc commit 114a1e8

1 file changed

Lines changed: 274 additions & 0 deletions

File tree

Lines changed: 274 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,274 @@
1+
//
2+
// NativeActivity.swift
3+
// SwiftAndroid
4+
//
5+
// Created by Alsey Coleman Miller on 2/27/26.
6+
//
7+
8+
#if os(Android)
9+
import Android
10+
import AndroidNDK
11+
#endif
12+
import AndroidLooper
13+
import AndroidFileManager
14+
import SystemPackage
15+
16+
/// Native Activity
17+
///
18+
/// This structure defines the native side of an android.app.NativeActivity.
19+
/// It is created by the framework, and handed to the application's native code as it is being launched.
20+
///
21+
/// [See Also](https://developer.android.com/ndk/reference/group/native-activity#anativeactivity)
22+
public struct NativeActivity: ~Copyable, Sendable {
23+
24+
// MARK: - Properties
25+
26+
internal let pointer: UnsafeMutablePointer<ANativeActivity>
27+
28+
// MARK: - Initialization
29+
30+
internal init(_ pointer: UnsafeMutablePointer<ANativeActivity>) {
31+
self.pointer = pointer
32+
}
33+
34+
// MARK: - Accessors
35+
36+
/// Pointer to the callback function table of the native application.
37+
///
38+
/// You can set the functions here to your own callbacks. The callbacks pointer itself is not immutable, so you must not call them directly. We recommend copying the callbacks to your own unique callbacks table and using those directly.
39+
public var callbacks: UnsafeMutablePointer<ANativeActivityCallbacks> {
40+
pointer.pointee.callbacks
41+
}
42+
43+
/// The global handle on the process's Java VM.
44+
public var javaVM: JavaVM {
45+
JavaVM(pointer.pointee.vm)
46+
}
47+
48+
/// JNI context for the main thread of the app.
49+
///
50+
/// Note that this field can ONLY be used from the main thread of the process; that is, the thread that calls into the ANativeActivityCallbacks.
51+
public var javaEnvironment: JNIEnvironment {
52+
JNIEnvironment(pointer.pointee.env)
53+
}
54+
55+
/// The NativeActivity object handle.
56+
///
57+
/// This is the native instance of the android.app.NativeActivity Java class.
58+
public var javaActivity: jobject {
59+
pointer.pointee.clazz
60+
}
61+
62+
/// Path to this application's internal data directory.
63+
public var internalDataPath: FilePath {
64+
FilePath(String(cString: pointer.pointee.internalDataPath))
65+
}
66+
67+
/// Path to this application's external (removable/mountable) data directory.
68+
public var externalDataPath: FilePath {
69+
FilePath(String(cString: pointer.pointee.externalDataPath))
70+
}
71+
72+
/// The platform's SDK version code.
73+
public var sdkVersion: Int32 {
74+
pointer.pointee.sdkVersion
75+
}
76+
77+
/// This is the native instance of the application.
78+
///
79+
/// It is not used by the framework, but can be set by the application to its own instance state.
80+
public var instance: UnsafeMutableRawPointer? {
81+
get { pointer.pointee.instance }
82+
nonmutating set { pointer.pointee.instance = newValue }
83+
}
84+
85+
/// Pointer to the Asset Manager instance for the application.
86+
///
87+
/// The application uses this to access binary assets bundled inside its own .apk file.
88+
public var assetManager: AndroidFileManager.AssetManager {
89+
AndroidFileManager.AssetManager(pointer.pointee.assetManager)
90+
}
91+
92+
/// Available starting with Honeycomb: path to the directory containing the application's OBB files (if any).
93+
///
94+
/// If the app doesn't have any OBB files, this directory may not exist.
95+
public var obbPath: FilePath? {
96+
guard let path = pointer.pointee.obbPath else {
97+
return nil
98+
}
99+
return FilePath(String(cString: path))
100+
}
101+
}
102+
103+
// MARK: - JavaVM
104+
105+
public struct JavaVM: ~Copyable, Sendable {
106+
107+
internal let pointer: UnsafeMutablePointer<JavaVM_>
108+
109+
internal init(_ pointer: UnsafeMutablePointer<JavaVM_>) {
110+
self.pointer = pointer
111+
}
112+
}
113+
114+
// MARK: - JNI Environment
115+
116+
public struct JNIEnvironment: ~Copyable, Sendable {
117+
118+
internal let pointer: UnsafeMutablePointer<JNIEnv>
119+
120+
internal init(_ pointer: UnsafeMutablePointer<JNIEnv>) {
121+
self.pointer = pointer
122+
}
123+
}
124+
125+
// MARK: - Native Activity Callbacks
126+
127+
/// These are the callbacks the framework makes into a native application.
128+
///
129+
/// All of these callbacks happen on the main thread of the application. By default, all callbacks are NULL; set to a pointer to your own function to have it called.
130+
///
131+
/// [See Also](https://developer.android.com/ndk/reference/struct/a-native-activity-callbacks)
132+
public struct NativeActivityCallbacks: Sendable {
133+
134+
/// NativeActivity has started.
135+
///
136+
/// See Java documentation for Activity.onStart() for more information.
137+
public var onStart: (@convention(c) (UnsafeMutablePointer<ANativeActivity>) -> Void)?
138+
139+
/// NativeActivity has resumed.
140+
///
141+
/// See Java documentation for Activity.onResume() for more information.
142+
public var onResume: (@convention(c) (UnsafeMutablePointer<ANativeActivity>) -> Void)?
143+
144+
/// Framework is asking NativeActivity to save its current instance state.
145+
///
146+
/// See Java documentation for Activity.onSaveInstanceState() for more information.
147+
/// The returned pointer needs to be created with malloc(); the framework will call free() on it for you.
148+
/// You also must fill in outSize with the number of bytes in the allocation. Note that the saved state will be persisted, so it can not contain any active entities (pointers to memory, file descriptors, etc).
149+
public var onSaveInstanceState: (@convention(c) (UnsafeMutablePointer<ANativeActivity>, UnsafeMutablePointer<Int>) -> UnsafeMutableRawPointer?)?
150+
151+
/// NativeActivity has paused.
152+
///
153+
/// See Java documentation for Activity.onPause() for more information.
154+
public var onPause: (@convention(c) (UnsafeMutablePointer<ANativeActivity>) -> Void)?
155+
156+
/// NativeActivity has stopped.
157+
///
158+
/// See Java documentation for Activity.onStop() for more information.
159+
public var onStop: (@convention(c) (UnsafeMutablePointer<ANativeActivity>) -> Void)?
160+
161+
/// NativeActivity is being destroyed.
162+
///
163+
/// See Java documentation for Activity.onDestroy() for more information.
164+
public var onDestroy: (@convention(c) (UnsafeMutablePointer<ANativeActivity>) -> Void)?
165+
166+
/// Focus has changed in this NativeActivity's window.
167+
///
168+
/// This is often used, for example, to pause a game when it loses input focus.
169+
public var onWindowFocusChanged: (@convention(c) (UnsafeMutablePointer<ANativeActivity>, Int32) -> Void)?
170+
171+
/// The drawing window for this native activity has been created.
172+
///
173+
/// You can use the window pointer to draw.
174+
public var onNativeWindowCreated: (@convention(c) (UnsafeMutablePointer<ANativeActivity>, OpaquePointer?) -> Void)?
175+
176+
/// The drawing window for this native activity has been resized.
177+
///
178+
/// You should retrieve the new size from the window and ensure that your rendering in it now matches.
179+
public var onNativeWindowResized: (@convention(c) (UnsafeMutablePointer<ANativeActivity>, OpaquePointer?) -> Void)?
180+
181+
/// The drawing window for this native activity needs to be redrawn.
182+
///
183+
/// To avoid transient artifacts during screen changes (such as orientation change), applications should not return from this function until they have finished drawing their window in its current state.
184+
public var onNativeWindowRedrawNeeded: (@convention(c) (UnsafeMutablePointer<ANativeActivity>, OpaquePointer?) -> Void)?
185+
186+
/// The drawing window for this native activity is going to be destroyed.
187+
///
188+
/// You MUST ensure that you do not touch the window object after returning from this function: in the common case of drawing to the window from another thread, that means the implementation of this callback must properly synchronize with the other thread to stop its drawing before returning from here.
189+
public var onNativeWindowDestroyed: (@convention(c) (UnsafeMutablePointer<ANativeActivity>, OpaquePointer?) -> Void)?
190+
191+
/// The input queue for this native activity's window has been created.
192+
///
193+
/// You can use it to monitor user input events.
194+
public var onInputQueueCreated: (@convention(c) (UnsafeMutablePointer<ANativeActivity>, OpaquePointer?) -> Void)?
195+
196+
/// The input queue for this native activity's window is being destroyed.
197+
///
198+
/// You should no longer try to reference it. Pending events may still be delivered.
199+
public var onInputQueueDestroyed: (@convention(c) (UnsafeMutablePointer<ANativeActivity>, OpaquePointer?) -> Void)?
200+
201+
/// The rectangle in the window in which content should be placed has changed.
202+
public var onContentRectChanged: (@convention(c) (UnsafeMutablePointer<ANativeActivity>, UnsafePointer<ARect>?) -> Void)?
203+
204+
/// The current device AConfiguration has changed.
205+
///
206+
/// The new configuration can be retrieved from assetManager.
207+
public var onConfigurationChanged: (@convention(c) (UnsafeMutablePointer<ANativeActivity>) -> Void)?
208+
209+
/// The system is running low on memory.
210+
///
211+
/// Try to reduce your memory use.
212+
public var onLowMemory: (@convention(c) (UnsafeMutablePointer<ANativeActivity>) -> Void)?
213+
}
214+
215+
// MARK: - Native Activity Functions
216+
217+
public extension NativeActivity {
218+
219+
/// Change the window format of the given activity.
220+
///
221+
/// Calls getWindow().setFormat() of the given activity.
222+
/// Note that this method can be called from any thread; it will send a message to the main thread of the process where the Java finish call will take place.
223+
func setWindowFormat(_ format: Int32) {
224+
ANativeActivity_setWindowFormat(pointer, format)
225+
}
226+
227+
/// Change the window flags of the given activity.
228+
///
229+
/// Calls getWindow().setFlags() of the given activity.
230+
/// Note that this method can be called from any thread; it will send a message to the main thread of the process where the Java finish call will take place. See window.h for flag constants.
231+
func setWindowFlags(addFlags: UInt32, removeFlags: UInt32) {
232+
ANativeActivity_setWindowFlags(pointer, addFlags, removeFlags)
233+
}
234+
235+
/// Show the IME while in the given activity.
236+
///
237+
/// Calls InputMethodManager.showSoftInput() for the given activity.
238+
/// Note that this method can be called from any thread; it will send a message to the main thread of the process where the Java finish call will take place.
239+
func showSoftInput(flags: UInt32) {
240+
ANativeActivity_showSoftInput(pointer, flags)
241+
}
242+
243+
/// Hide the IME while in the given activity.
244+
///
245+
/// Calls InputMethodManager.hideSoftInput() for the given activity.
246+
/// Note that this method can be called from any thread; it will send a message to the main thread of the process where the Java finish call will take place.
247+
func hideSoftInput(flags: UInt32) {
248+
ANativeActivity_hideSoftInput(pointer, flags)
249+
}
250+
251+
/// Finish the given activity.
252+
///
253+
/// Calls Activity.finish() on the Java object for the given activity.
254+
/// Note that this method can be called from any thread; it will send a message to the main thread of the process where the Java finish call will take place.
255+
func finish() {
256+
ANativeActivity_finish(pointer)
257+
}
258+
}
259+
260+
#if !os(Android)
261+
// Stubs for non-Android platforms
262+
private func ANativeActivity_setWindowFormat(_ activity: UnsafeMutablePointer<ANativeActivity>, _ format: Int32) { fatalError("stub") }
263+
private func ANativeActivity_setWindowFlags(_ activity: UnsafeMutablePointer<ANativeActivity>, _ addFlags: UInt32, _ removeFlags: UInt32) { fatalError("stub") }
264+
private func ANativeActivity_showSoftInput(_ activity: UnsafeMutablePointer<ANativeActivity>, _ flags: UInt32) { fatalError("stub") }
265+
private func ANativeActivity_hideSoftInput(_ activity: UnsafeMutablePointer<ANativeActivity>, _ flags: UInt32) { fatalError("stub") }
266+
private func ANativeActivity_finish(_ activity: UnsafeMutablePointer<ANativeActivity>) { fatalError("stub") }
267+
268+
public typealias ANativeActivity = OpaquePointer
269+
public typealias ANativeActivityCallbacks = OpaquePointer
270+
public typealias JavaVM_ = OpaquePointer
271+
public typealias JNIEnv = OpaquePointer
272+
public typealias jobject = OpaquePointer
273+
public typealias ARect = OpaquePointer
274+
#endif

0 commit comments

Comments
 (0)