├── .gitignore ├── CMakeLists.txt ├── JNI.swift ├── JNIArrays.swift.gyb ├── JNIClassManipulation.swift ├── JNIExceptions.swift ├── JNIFields.swift.gyb ├── JNIMethods.swift.gyb ├── JNIObjects.swift ├── JNIRefs.swift ├── JNIStrings.swift ├── LICENSE ├── README.md ├── SwiftJNI.swift └── module.map.in /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata 19 | 20 | ## Other 21 | *.xccheckout 22 | *.moved-aside 23 | *.xcuserstate 24 | *.xcscmblueprint 25 | 26 | ## Obj-C/Swift specific 27 | *.hmap 28 | *.ipa 29 | 30 | # Swift Package Manager 31 | # 32 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 33 | # Packages/ 34 | .build/ 35 | 36 | # CocoaPods 37 | # 38 | # We recommend against adding the Pods directory to your .gitignore. However 39 | # you should judge for yourself, the pros and cons are mentioned at: 40 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 41 | # 42 | # Pods/ 43 | 44 | # Carthage 45 | # 46 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 47 | # Carthage/Checkouts 48 | 49 | Carthage/Build 50 | 51 | # fastlane 52 | # 53 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 54 | # screenshots whenever they are needed. 55 | # For more information about the recommended setup visit: 56 | # https://github.com/fastlane/fastlane/blob/master/docs/Gitignore.md 57 | 58 | fastlane/report.xml 59 | fastlane/screenshots 60 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(sources 2 | JNI.swift 3 | JNIArrays.swift.gyb 4 | JNIClassManipulation.swift 5 | JNIExceptions.swift 6 | JNIFields.swift.gyb 7 | JNIMethods.swift.gyb 8 | JNIObjects.swift 9 | JNIRefs.swift 10 | JNIStrings.swift 11 | SwiftJNI.swift 12 | ) 13 | 14 | set(output_dir "${SWIFTLIB_DIR}/jni") 15 | 16 | # Set correct paths to glibc headers 17 | set(JNI_INCLUDE_PATH "${SWIFT_SDK_ANDROID_PATH}/usr/include") 18 | if (NOT EXISTS "${JNI_INCLUDE_PATH}/jni.h") 19 | message(FATAL_ERROR "JNI header was not found at ${JNI_INCLUDE_PATH}.") 20 | endif() 21 | 22 | # Generate module.map 23 | configure_file(module.map.in "${CMAKE_CURRENT_BINARY_DIR}/module.map" @ONLY) 24 | 25 | add_custom_command_target(unused_var 26 | COMMAND 27 | "${CMAKE_COMMAND}" "-E" "make_directory" "${output_dir}" 28 | COMMAND 29 | "${CMAKE_COMMAND}" "-E" "copy_if_different" 30 | "${CMAKE_CURRENT_BINARY_DIR}/module.map" 31 | "${output_dir}/module.map" 32 | CUSTOM_TARGET_NAME "copy_jni_module" 33 | OUTPUT "${output_dir}/module.map" "${output_dir}" 34 | DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/module.map" 35 | COMMENT "Copying JNI module to ${output_dir}") 36 | 37 | swift_install_in_component(stdlib 38 | FILES "${output_dir}/module.map" 39 | DESTINATION "lib/swift/jni") 40 | 41 | add_swift_library(swiftJNI IS_SDK_OVERLAY 42 | ${sources} 43 | FILE_DEPENDS copy_jni_module "${output_dir}" 44 | TARGET_SDKS ANDROID 45 | INSTALL_IN_COMPONENT stdlib-experimental) 46 | -------------------------------------------------------------------------------- /JNI.swift: -------------------------------------------------------------------------------- 1 | @_exported import CJNI // Clang module 2 | 3 | public class JNI { 4 | /// Our reference to the Java Virtual Machine, to be set on init 5 | let _jvm: UnsafeMutablePointer 6 | 7 | /// Ensure the _env pointer we have is always attached to the JVM 8 | var _env: UnsafeMutablePointer { 9 | let jvm = _jvm.memory.memory 10 | 11 | // The type `JNIEnv` is defined as a non-mutable pointer, 12 | // so use this mutable _tmpPointer as an intermediate: 13 | var _tmpPointer = UnsafeMutablePointer() 14 | let threadStatus = jvm.GetEnv(_jvm, &_tmpPointer, jint(JNI_VERSION_1_6)) 15 | var _env = UnsafeMutablePointer(_tmpPointer) 16 | 17 | switch threadStatus { 18 | case JNI_OK: break // if we're already attached, do nothing 19 | case JNI_EDETACHED: 20 | // We weren't attached to the Java UI thread 21 | jvm.AttachCurrentThread(_jvm, &_env, nil) 22 | case JNI_EVERSION: 23 | fatalError("This version of JNI is not supported") 24 | default: break 25 | } 26 | 27 | return _env 28 | } 29 | 30 | // Normally we init the jni global ourselves in JNI_OnLoad 31 | public init?(jvm: UnsafeMutablePointer) { 32 | if jvm == nil { return nil } 33 | self._jvm = jvm 34 | } 35 | } 36 | 37 | public extension JNI { 38 | public func GetVersion() -> jint { 39 | let env = self._env 40 | return env.memory.memory.GetVersion(env) 41 | } 42 | 43 | public func GetJavaVM(vm: UnsafeMutablePointer>) -> jint { 44 | let env = self._env 45 | return env.memory.memory.GetJavaVM(env, vm) 46 | } 47 | 48 | public func RegisterNatives(targetClass: jclass, _ methods: UnsafePointer, _ nMethods: jint) -> jint { 49 | let env = self._env 50 | return env.memory.memory.RegisterNatives(env, targetClass, methods, nMethods) 51 | } 52 | 53 | public func UnregisterNatives(targetClass: jclass) -> jint { 54 | let env = self._env 55 | return env.memory.memory.UnregisterNatives(env, targetClass) 56 | } 57 | 58 | public func MonitorEnter(obj: jobject) -> jint { 59 | let env = self._env 60 | return env.memory.memory.MonitorEnter(env, obj) 61 | } 62 | 63 | public func MonitorExit(obj: jobject) -> jint { 64 | let env = self._env 65 | return env.memory.memory.MonitorExit(env, obj) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /JNIArrays.swift.gyb: -------------------------------------------------------------------------------- 1 | import CJNI 2 | 3 | %{ 4 | jTypes = [ 5 | 6 | # You can only set / get one jobject array element at a time 7 | # So we handle that case manually, and automate the rest... 8 | # ('Object', 'jobject'), 9 | 10 | ('Boolean', 'jboolean'), 11 | ('Byte', 'jbyte'), 12 | ('Char', 'jchar'), 13 | ('Short', 'jshort'), 14 | ('Int', 'jint'), 15 | ('Long', 'jlong'), 16 | ('Float', 'jfloat'), 17 | ('Double', 'jdouble') 18 | ] 19 | }% 20 | 21 | public extension JNI { 22 | 23 | public func GetArrayLength(array: jarray) -> jsize { 24 | let env = self._env 25 | return env.memory.memory.GetArrayLength(env, array) 26 | } 27 | 28 | % # You can only set / get one object element at a time 29 | public func NewObjectArray(length: jsize, _ elementClass: jclass, _ initialElement: jobject) -> jobjectArray { 30 | let env = self._env 31 | return env.memory.memory.NewObjectArray(env, length, elementClass, initialElement) 32 | } 33 | 34 | public func GetObjectArrayElement(array: jobjectArray, _ index: jsize) -> jobject { 35 | let env = self._env 36 | return env.memory.memory.GetObjectArrayElement(env, array, index) 37 | } 38 | 39 | public func SetObjectArrayElement(array: jobjectArray, _ index: jsize, _ value: jobject) { 40 | let env = self._env 41 | env.memory.memory.SetObjectArrayElement(env, array, index, value) 42 | } 43 | 44 | 45 | % # But we can automate the rest 46 | % for (TypeName, type) in jTypes: 47 | 48 | public func New${TypeName}Array(length: jsize) -> ${type}Array { 49 | let env = self._env 50 | return env.memory.memory.New${TypeName}Array(env, length) 51 | } 52 | 53 | public func Get${TypeName}ArrayElements(array: ${type}Array, _ isCopy: UnsafeMutablePointer) -> UnsafeMutablePointer<${type}> { 54 | let env = self._env 55 | return env.memory.memory.Get${TypeName}ArrayElements(env, array, isCopy) 56 | } 57 | 58 | public func Release${TypeName}ArrayElements(array: ${type}Array, _ elems: UnsafeMutablePointer<${type}>, _ mode: jint) { 59 | let env = self._env 60 | env.memory.memory.Release${TypeName}ArrayElements(env, array, elems, mode) 61 | } 62 | 63 | public func Get${TypeName}ArrayRegion(array: ${type}Array, _ start: jsize, _ len: jsize, _ buf: UnsafeMutablePointer<${type}>) { 64 | let env = self._env 65 | env.memory.memory.Get${TypeName}ArrayRegion(env, array, start, len, buf) 66 | } 67 | 68 | public func Set${TypeName}ArrayRegion(array: ${type}Array, _ start: jsize, _ len: jsize, _ buf: UnsafePointer<${type}>) { 69 | let env = self._env 70 | env.memory.memory.Set${TypeName}ArrayRegion(env, array, start, len, buf) 71 | } 72 | 73 | % end 74 | } 75 | 76 | /// High performance JNI extensions 77 | public extension JNI { 78 | public func GetPrimitiveArrayCritical(array: jarray, _ isCopy: UnsafeMutablePointer) -> UnsafeMutablePointer { 79 | let env = self._env 80 | return env.memory.memory.GetPrimitiveArrayCritical(env, array, isCopy) 81 | } 82 | 83 | public func ReleasePrimitiveArrayCritical(array: jarray, _ carray: UnsafeMutablePointer, _ mode: jint) { 84 | let env = self._env 85 | env.memory.memory.ReleasePrimitiveArrayCritical(env, array, carray, mode) 86 | } 87 | 88 | public func NewDirectByteBuffer(address: UnsafeMutablePointer, _ capacity: jlong) -> jobject { 89 | let env = self._env 90 | return env.memory.memory.NewDirectByteBuffer(env, address, capacity) 91 | } 92 | 93 | public func GetDirectBufferAddress(buf: jobject) -> UnsafeMutablePointer { 94 | let env = self._env 95 | return env.memory.memory.GetDirectBufferAddress(env, buf) 96 | } 97 | 98 | public func GetDirectBufferCapacity(buf: jobject) -> jlong { 99 | let env = self._env 100 | return env.memory.memory.GetDirectBufferCapacity(env, buf) 101 | } 102 | } 103 | 104 | // ${'Local Variables'}: 105 | // eval: (read-only-mode 1) 106 | // End: 107 | -------------------------------------------------------------------------------- /JNIClassManipulation.swift: -------------------------------------------------------------------------------- 1 | import CJNI 2 | 3 | public extension JNI { 4 | public func DefineClass(name: String, _ loader: jobject, _ buffer: UnsafePointer, _ bufferLength: jsize) -> jclass { 5 | let env = self._env 6 | return env.memory.memory.DefineClass(env, name, loader, buffer, bufferLength) 7 | } 8 | 9 | public func FindClass(name: String) -> jclass { 10 | let env = self._env 11 | return env.memory.memory.FindClass(env, name) 12 | } 13 | 14 | public func FromReflectedMethod(method: jobject) -> jmethodID { 15 | let env = self._env 16 | return env.memory.memory.FromReflectedMethod(env, method) 17 | } 18 | 19 | public func FromReflectedField(field: jobject) -> jfieldID { 20 | let env = self._env 21 | return env.memory.memory.FromReflectedField(env, field) 22 | } 23 | 24 | public func ToReflectedMethod(targetClass: jclass, _ methodID: jmethodID, _ isStatic: jboolean) -> jobject { 25 | let env = self._env 26 | return env.memory.memory.ToReflectedMethod(env, cls, methodID, isStatic) 27 | } 28 | 29 | public func GetSuperclass(targetClass: jclass) -> jclass { 30 | let env = self._env 31 | return env.memory.memory.GetSuperclass(env, targetClass) 32 | } 33 | 34 | public func IsAssignableFrom(classA: jclass, _ classB: jclass) -> jboolean { 35 | let env = self._env 36 | return env.memory.memory.IsAssignableFrom(env, classA, classB) 37 | } 38 | 39 | public func ToReflectedField(targetClass: jclass, _ fieldID: jfieldID, _ isStatic: jboolean) -> jobject { 40 | let env = self._env 41 | return env.memory.memory.ToReflectedField(env, cls, fieldID, isStatic) 42 | } 43 | } -------------------------------------------------------------------------------- /JNIExceptions.swift: -------------------------------------------------------------------------------- 1 | import CJNI 2 | 3 | public extension JNI { 4 | public func ExceptionCheck() -> jboolean { 5 | let env = self._env 6 | return env.memory.memory.ExceptionCheck(env) 7 | } 8 | 9 | public func ExceptionDescribe() { 10 | let env = self._env 11 | env.memory.memory.ExceptionDescribe(env) 12 | } 13 | 14 | public func ExceptionClear() { 15 | let env = self._env 16 | env.memory.memory.ExceptionClear(env) 17 | } 18 | 19 | public func ExceptionOccurred() -> jthrowable { 20 | let env = self._env 21 | return env.memory.memory.ExceptionOccurred(env) 22 | } 23 | 24 | public func Throw(obj: jthrowable) -> jint { 25 | let env = self._env 26 | return env.memory.memory.Throw(env, obj) 27 | } 28 | 29 | public func ThrowNew(targetClass: jclass, _ message: String) -> jint { 30 | let env = self._env 31 | return env.memory.memory.ThrowNew(env, targetClass, message) 32 | } 33 | 34 | public func FatalError(msg: String) { 35 | let env = self._env 36 | env.memory.memory.FatalError(env, msg) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /JNIFields.swift.gyb: -------------------------------------------------------------------------------- 1 | // Hash maps and fields 2 | 3 | import CJNI 4 | 5 | %{ 6 | jTypes = [ 7 | ('Object', 'jobject'), 8 | ('Boolean', 'jboolean'), 9 | ('Byte', 'jbyte'), 10 | ('Char', 'jchar'), 11 | ('Short', 'jshort'), 12 | ('Int', 'jint'), 13 | ('Long', 'jlong'), 14 | ('Float', 'jfloat'), 15 | ('Double', 'jdouble') 16 | ] 17 | }% 18 | 19 | public extension JNI { 20 | 21 | public func GetFieldID(targetClass: jclass, _ name: String, _ sig: String) -> jfieldID { 22 | let env = self._env 23 | return env.memory.memory.GetFieldID(env, targetClass, name, sig) 24 | } 25 | 26 | public func GetStaticFieldID(targetClass: jclass, _ name: String, _ sig: String) -> jfieldID { 27 | let env = self._env 28 | return env.memory.memory.GetStaticFieldID(env, targetClass, name, sig) 29 | } 30 | 31 | % for (TypeName, Type) in jTypes: 32 | public func Get${TypeName}Field(obj: jobject, _ fieldID: jfieldID) -> ${Type} { 33 | let env = self._env 34 | return env.memory.memory.Get${TypeName}Field(env, obj, fieldID) 35 | } 36 | 37 | public func Set${TypeName}Field(obj: jobject, _ fieldID: jfieldID, _ value: ${Type}) { 38 | let env = self._env 39 | env.memory.memory.Set${TypeName}Field(env, obj, fieldID, value) 40 | } 41 | 42 | public func GetStatic${TypeName}Field(targetClass: jclass, _ fieldID: jfieldID) -> ${Type} { 43 | let env = self._env 44 | return env.memory.memory.GetStatic${TypeName}Field(env, targetClass, fieldID) 45 | } 46 | 47 | public func SetStatic${TypeName}Field(targetClass: jclass, _ fieldID: jfieldID, _ value: ${Type}) { 48 | let env = self._env 49 | env.memory.memory.SetStatic${TypeName}Field(env, targetClass, fieldID, value) 50 | } 51 | % end 52 | } 53 | 54 | // ${'Local Variables'}: 55 | // eval: (read-only-mode 1) 56 | // End: 57 | -------------------------------------------------------------------------------- /JNIMethods.swift.gyb: -------------------------------------------------------------------------------- 1 | //===--- JNIMethods.swift.gyb ---------------------------------*- swift -*-===// 2 | // 3 | // This source file is part of the Swift.org open source project 4 | // 5 | // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See http://swift.org/LICENSE.txt for license information 9 | // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | import CJNI 14 | 15 | %{ 16 | jTypes = [ 17 | ('Void', 'Void'), # returning Void is also valid in swift 18 | ('Object', 'jobject'), 19 | ('Boolean', 'jboolean'), 20 | ('Byte', 'jbyte'), 21 | ('Char', 'jchar'), 22 | ('Short', 'jshort'), 23 | ('Int', 'jint'), 24 | ('Long', 'jlong'), 25 | ('Float', 'jfloat'), 26 | ('Double', 'jdouble') 27 | ] 28 | }% 29 | 30 | 31 | public extension JNI { 32 | 33 | % # Standard Java method calls 34 | 35 | public func GetMethodID(targetClass: jclass, methodName name: String, methodSignature sig: String) -> jmethodID? { 36 | let env = self._env 37 | let result = env.memory.memory.GetMethodID(env, targetClass, name, sig) 38 | return (result == nil) ? .None : result 39 | } 40 | 41 | %for (TypeName, type) in jTypes: 42 | 43 | public func Call${TypeName}Method(obj: jobject, _ methodID: jmethodID, _ args: jvalue...) -> ${type} { 44 | return Call${TypeName}MethodA(obj, _ methodID: methodID, _ args: args) 45 | } 46 | 47 | @available(*, unavailable, message="CVaListPointers are not supported, use `Call${TypeName}Method` or `Call${TypeName}MethodA` instead") 48 | public func Call${TypeName}MethodV(obj: jobject, _ methodID: jmethodID, _ args: CVaListPointer) -> ${type} { 49 | // let env = self._env 50 | // return env.memory.memory.Call${TypeName}MethodV(env, obj, methodID, args) 51 | return ${type}() 52 | } 53 | 54 | public func Call${TypeName}MethodA(obj: jobject, _ methodID: jmethodID, _ args: [jvalue]) -> ${type} { 55 | let env = self._env 56 | var mutableArgs = args 57 | return env.memory.memory.Call${TypeName}MethodA(env, obj, methodID, &mutableArgs) 58 | } 59 | 60 | %end #standard methods 61 | 62 | 63 | 64 | % # Nonvirtual Java method calls 65 | %for (TypeName, type) in jTypes: 66 | 67 | public func CallNonvirtual${TypeName}Method(obj: jobject, _ targetClass: jclass, _ methodID: jmethodID, _ args: jvalue...) -> ${type} { 68 | return self.CallNonvirtual${TypeName}MethodA(obj, _ targetClass: targetClass, _ methodID: methodID, _ args: args) 69 | } 70 | 71 | @available(*, unavailable, message="CVaListPointers are not supported, use `CallNonvirtual${TypeName}Method` or `CallNonvirtual${TypeName}MethodA` instead") 72 | public func CallNonvirtual${TypeName}MethodV(obj: jobject, _ targetClass: jclass, _ methodID: jmethodID, _ args: CVaListPointer) -> ${type} { 73 | // let env = self._env 74 | // return env.memory.memory.CallNonvirtual${TypeName}MethodV(env, obj, methodID, args) 75 | return ${type}() 76 | } 77 | 78 | public func CallNonvirtual${TypeName}MethodA(obj: jobject, _ targetClass: jclass, _ methodID: jmethodID, _ args: [jvalue]) -> ${type} { 79 | let env = self._env 80 | var mutableArgs = args 81 | return env.memory.memory.CallNonvirtual${TypeName}MethodA(env, obj, targetClass, methodID, &mutableArgs) 82 | } 83 | 84 | %end #nonvirtual methods 85 | 86 | 87 | 88 | %# Static Java method calls 89 | 90 | public func GetStaticMethodID(targetClass: jclass, _ name: String, _ sig: String) -> jmethodID { 91 | let env = self._env 92 | return env.memory.memory.GetStaticMethodID(env, targetClass, name, sig) 93 | } 94 | 95 | %for (TypeName, type) in jTypes: 96 | 97 | public func CallStatic${TypeName}Method(targetClass: jclass, _ methodID: jmethodID, _ args: jvalue...) -> ${type} { 98 | return CallStatic${TypeName}MethodA(targetClass, _ methodID: methodID, _ args: args) 99 | } 100 | 101 | @available(*, unavailable, message="CVaListPointers are not supported, use `CallStatic${TypeName}Method` or `CallStatic${TypeName}MethodA` instead") 102 | public func CallStatic${TypeName}MethodV(targetClass: jclass, _ methodID: jmethodID, _ args: CVaListPointer) -> ${type} { 103 | // let env = self._env 104 | // return env.memory.memory.CallStatic${TypeName}MethodV(env, class, methodID, args) 105 | return ${type}() 106 | } 107 | 108 | public func CallStatic${TypeName}MethodA(targetClass: jclass, _ methodID: jmethodID, _ args: [jvalue]) -> ${type} { 109 | let env = self._env 110 | var mutableArgs = args 111 | return env.memory.memory.CallStatic${TypeName}MethodA(env, targetClass, methodID, &mutableArgs) 112 | } 113 | 114 | %end #static methods 115 | } 116 | 117 | // ${'Local Variables'}: 118 | // eval: (read-only-mode 1) 119 | // End: 120 | 121 | -------------------------------------------------------------------------------- /JNIObjects.swift: -------------------------------------------------------------------------------- 1 | import CJNI 2 | 3 | public extension JNI { 4 | 5 | public func AllocObject(targetClass: jclass) -> jobject { 6 | let env = self._env 7 | return env.memory.memory.AllocObject(env, targetClass) 8 | } 9 | 10 | public func NewObject(targetClass: jclass, _ methodID: jmethodID, _ args: jvalue...) -> jobject { 11 | return self.NewObjectA(targetClass, _ methodID: methodID, _ args: args) 12 | } 13 | 14 | @available(*, unavailable, message="CVaListPointer unavailable, use NewObject or NewObjectA") 15 | public func NewObjectV(targetClass: jclass, _ methodID: jmethodID, _ args: CVaListPointer) -> jobject { 16 | // let env = self._env 17 | // return env.memory.memory.NewObjectV(env, targetClass, methodID, args) 18 | return jobject() 19 | } 20 | 21 | public func NewObjectA(targetClass: jclass, _ methodID: jmethodID, _ args: [jvalue]) -> jobject { 22 | let env = self._env 23 | var mutableArgs = args 24 | return env.memory.memory.NewObjectA(env, targetClass, methodID, &mutableArgs) 25 | } 26 | 27 | public func GetObjectClass(obj: jobject) -> jclass? { 28 | let env = self._env 29 | let result = env.memory.memory.GetObjectClass(env, obj) 30 | return (result != nil) ? result : .None 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /JNIRefs.swift: -------------------------------------------------------------------------------- 1 | import CJNI 2 | 3 | public extension JNI { 4 | public func NewGlobalRef(obj: jobject) -> jobject { 5 | let env = self._env 6 | return env.memory.memory.NewGlobalRef(env, obj) 7 | } 8 | 9 | public func DeleteGlobalRef(globalRef: jobject) { 10 | let env = self._env 11 | env.memory.memory.DeleteGlobalRef(env, globalRef) 12 | } 13 | 14 | public func NewLocalRef(ref: jobject) -> jobject { 15 | let env = self._env 16 | return env.memory.memory.NewLocalRef(env, ref) 17 | } 18 | 19 | public func DeleteLocalRef(localRef: jobject) { 20 | let env = self._env 21 | env.memory.memory.DeleteLocalRef(env, localRef) 22 | } 23 | 24 | public func PushLocalFrame(capacity: jint) -> jint { 25 | let env = self._env 26 | return env.memory.memory.PushLocalFrame(env, capacity) 27 | } 28 | 29 | public func PopLocalFrame(result: jobject) -> jobject { 30 | let env = self._env 31 | return env.memory.memory.PopLocalFrame(env, result) 32 | } 33 | 34 | public func EnsureLocalCapacity(capacity: jint) -> jint { 35 | let env = self._env 36 | return env.memory.memory.EnsureLocalCapacity(env, capacity) 37 | } 38 | 39 | public func IsSameObject(ref1: jobject, _ ref2: jobject) -> jboolean { 40 | let env = self._env 41 | return env.memory.memory.IsSameObject(env, ref1, ref2) 42 | } 43 | 44 | public func IsInstanceOf(obj: jobject, _ targetClass: jclass) -> jboolean { 45 | let env = self._env 46 | return env.memory.memory.IsInstanceOf(env, obj, targetClass) 47 | } 48 | 49 | public func NewWeakGlobalRef(obj: jobject) -> jweak { 50 | let env = self._env 51 | return env.memory.memory.NewWeakGlobalRef(env, obj) 52 | } 53 | 54 | public func DeleteWeakGlobalRef(obj: jweak) { 55 | let env = self._env 56 | env.memory.memory.DeleteWeakGlobalRef(env, obj) 57 | } 58 | 59 | /* added in 1: JNI.6 */ 60 | public func GetObjectRefType(obj: jobject) -> jobjectRefType { 61 | let env = self._env 62 | return env.memory.memory.GetObjectRefType(env, obj) 63 | } 64 | } -------------------------------------------------------------------------------- /JNIStrings.swift: -------------------------------------------------------------------------------- 1 | import CJNI 2 | 3 | public extension JNI { 4 | public func NewString(unicodeChars: UnsafePointer, _ len: jsize) -> jstring { 5 | let env = self._env 6 | return env.memory.memory.NewString(env, unicodeChars, len) 7 | } 8 | 9 | public func GetStringLength(string: jstring) -> jsize { 10 | let env = self._env 11 | return env.memory.memory.GetStringLength(env, string) 12 | } 13 | 14 | public func GetStringChars(string: jstring, _ isCopy: UnsafeMutablePointer) -> UnsafePointer { 15 | let env = self._env 16 | return env.memory.memory.GetStringChars(env, string, isCopy) 17 | } 18 | 19 | public func ReleaseStringChars(string: jstring, _ chars: UnsafePointer) { 20 | let env = self._env 21 | env.memory.memory.ReleaseStringChars(env, string, chars) 22 | } 23 | 24 | public func NewStringUTF(bytes: String) -> jstring { 25 | let env = self._env 26 | return env.memory.memory.NewStringUTF(env, bytes) 27 | } 28 | 29 | public func GetStringUTFLength(string: jstring) -> jsize { 30 | let env = self._env 31 | return env.memory.memory.GetStringUTFLength(env, string) 32 | } 33 | 34 | public func GetStringUTFChars(string: jstring, _ isCopy: UnsafeMutablePointer) -> String { 35 | let env = self._env 36 | return String(env.memory.memory.GetStringUTFChars(env, string, isCopy)) 37 | } 38 | 39 | public func ReleaseStringUTFChars(string: jstring, _ utf: String) { 40 | let env = self._env 41 | env.memory.memory.ReleaseStringUTFChars(env, string, utf) 42 | } 43 | 44 | public func GetStringRegion(str: jstring, _ start: jsize, _ len: jsize, _ buf: UnsafeMutablePointer) { 45 | let env = self._env 46 | env.memory.memory.GetStringRegion(env, str, start, len, buf) 47 | } 48 | 49 | public func GetStringUTFRegion(str: jstring, _ start: jsize, _ len: jsize, _ buf: UnsafeMutablePointer) { 50 | let env = self._env 51 | env.memory.memory.GetStringUTFRegion(env, str, start, len, buf) 52 | } 53 | 54 | public func GetStringCritical(string: jstring, _ isCopy: UnsafeMutablePointer) -> UnsafePointer { 55 | let env = self._env 56 | return env.memory.memory.GetStringCritical(env, string, isCopy) 57 | } 58 | 59 | public func ReleaseStringCritical(string: jstring, _ carray: UnsafePointer) { 60 | let env = self._env 61 | env.memory.memory.ReleaseStringCritical(env, string, carray) 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # swift-jni 2 | 3 | The start of a JNI wrapper for swift-android (later for other platforms too, presumably) 4 | 5 | It uses a Swift-like API wherever possible. i.e., GetIntArrayRegion returns [Int], and other JNI methods may take Int as a param instead of jsize etc. Oftentimes however it wouldn't make sense to take or return anything but the raw JNI pointer (e.g. NewIntArray, NewGlobalRef etc.) 6 | 7 | The naming has been kept as close to the C-functions as possible, including omiting parameter names, and documenting differences where not immediately obvious. That way the vast majority of documentation is done for us via the JNI docs. 8 | 9 | # Usage 10 | 11 | Internally the module uses JNI_OnLoad (which could be problematic if the user wants to use their own) to initialise an implicitly unwrapped global, `jni`. 12 | 13 | This global can be then used from Swift code (from any thread) to run standard JNI functions like jni.GetIntArrayRegion(jarray), to return an array of Swift `Int`s 14 | 15 | See the article here for why (and a bit of how) this project came to be: https://medium.com/@ephemer/using-jni-in-swift-to-put-an-app-into-the-android-play-store-732e542a99dd#.rtviqfdlu 16 | -------------------------------------------------------------------------------- /SwiftJNI.swift: -------------------------------------------------------------------------------- 1 | import CJNI 2 | 3 | public var jni: JNI! // this gets set "OnLoad" so should always exist 4 | 5 | @_silgen_name("JNI_OnLoad") 6 | public func JNI_OnLoad(jvm: UnsafeMutablePointer, reserved: UnsafeMutablePointer) -> jint { 7 | 8 | guard let localJNI = JNI(jvm: jvm) else { 9 | fatalError("Couldn't initialise JNI") 10 | } 11 | 12 | jni = localJNI // set the global for use elsewhere 13 | 14 | return JNI_VERSION_1_6 15 | } 16 | 17 | extension jboolean : BooleanLiteralConvertible { 18 | public init(booleanLiteral value: Bool) { 19 | self = value ? jboolean(JNI_TRUE) : jboolean(JNI_FALSE) 20 | } 21 | } 22 | 23 | // SwiftJNI Public API 24 | public class SwiftJNI : JNI { 25 | public func RegisterNatives(jClass: jclass, methods: [JNINativeMethod]) -> Bool { 26 | let _env = self._env 27 | let env = _env.memory.memory 28 | let result = env.RegisterNatives(_env, jClass, methods, jint(methods.count)) 29 | return (result == 0) 30 | } 31 | 32 | public func ThrowNew(message: String) { 33 | let _env = self._env 34 | let env = _env.memory.memory 35 | env.ThrowNew(_env, env.FindClass(_env, "java/lang/Exception"), message) 36 | } 37 | 38 | /// - Note: This shouldn't need to be cleaned up because we're not taking ownership of the reference 39 | public func GetStringUTFChars(string: jstring) -> UnsafePointer { 40 | let _env = self._env 41 | var didCopyStringChars = jboolean() // XXX: this gets set below, check it! 42 | return _env.memory.memory.GetStringUTFChars(_env, string, &didCopyStringChars) 43 | } 44 | 45 | // MARK: References 46 | 47 | public func NewGlobalRef(object: jobject) -> jobject? { 48 | let _env = self._env 49 | let result = _env.memory.memory.NewGlobalRef(_env, object) 50 | return (result != nil) ? result : .None 51 | } 52 | 53 | // MARK: Classes and Methods 54 | 55 | public func FindClass(className: String) -> jclass? { 56 | let _env = self._env 57 | let result = _env.memory.memory.FindClass(_env, className) 58 | return (result != nil) ? result : .None 59 | } 60 | 61 | public func GetMethodID(javaClass: jclass, methodName: UnsafePointer, methodSignature: UnsafePointer) -> jmethodID? { 62 | let _env = self._env 63 | let result = _env.memory.memory.GetMethodID(_env, javaClass, methodName, methodSignature) 64 | return (result != nil) ? result : .None 65 | } 66 | 67 | // TODO: make parameters take [JValue], being a swifty version of [jvalue] with reference counting etc. 68 | public func CallVoidMethodA(object: jobject, methodID method: jmethodID, parameters: [jvalue]) { 69 | let _env = self._env 70 | var methodArgs = parameters 71 | _env.memory.memory.CallVoidMethodA(_env, object, method, &methodArgs) 72 | } 73 | 74 | // MARK: Arrays 75 | 76 | public func GetArrayLength(array: jarray) -> Int { 77 | let _env = self._env 78 | let result = _env.memory.memory.GetArrayLength(_env, array) 79 | return Int(result) 80 | } 81 | 82 | public func NewIntArray(count: Int) -> jarray? { 83 | let _env = self._env 84 | let result = _env.memory.memory.NewIntArray(_env, jsize(count)) 85 | return (result != nil) ? result : .None 86 | } 87 | 88 | public func GetIntArrayRegion(array: jintArray, startIndex: Int = 0, numElements: Int = -1) -> [Int] { 89 | let _env = self._env 90 | var count = numElements 91 | 92 | if numElements < 0 { 93 | count = GetArrayLength(array) 94 | } 95 | 96 | var result = [jint](count: count, repeatedValue: 0) 97 | _env.memory.memory.GetIntArrayRegion(_env, array, jsize(startIndex), jsize(count), &result) 98 | return result.map { Int($0) } 99 | } 100 | 101 | public func SetIntArrayRegion(array: jintArray, startIndex: Int = 0, from sourceElements: [Int]) { 102 | let _env = self._env 103 | var newElements = sourceElements.map { jint($0) } // make mutable copy 104 | _env.memory.memory.SetIntArrayRegion(_env, array, jsize(startIndex), jsize(newElements.count), &newElements) 105 | } 106 | 107 | public func NewFloatArray(count: Int) -> jarray? { 108 | let _env = self._env 109 | let result = _env.memory.memory.NewFloatArray(_env, jsize(count)) 110 | return (result != nil) ? result : .None 111 | } 112 | 113 | public func GetFloatArrayRegion(array: jfloatArray, startIndex: Int = 0, numElements: Int = -1) -> [Float] { 114 | let _env = self._env 115 | var count = numElements 116 | 117 | if numElements < 0 { 118 | count = GetArrayLength(array) 119 | } 120 | 121 | var result = [jfloat](count: count, repeatedValue: 0) 122 | _env.memory.memory.GetFloatArrayRegion(_env, array, jsize(startIndex), jsize(count), &result) 123 | return result.map { Float($0) } 124 | } 125 | 126 | public func SetFloatArrayRegion(array: jfloatArray, startIndex: Int = 0, from sourceElements: [Float]) { 127 | let _env = self._env 128 | var newElements = sourceElements.map { jfloat($0) } // make mutable copy 129 | _env.memory.memory.SetFloatArrayRegion(_env, array, jsize(startIndex), jsize(newElements.count), &newElements) 130 | } 131 | } 132 | 133 | 134 | /** 135 | Allows a (Void) Java method to be called from Swift. Takes a global jobj (a class instance), a method name and its signature. The resulting callback can be called via javaCallback.call(param1, param2...), or javaCallback.apply([params]). Each param must be a jvalue. 136 | 137 | Needs more error checking and handling. The basis is there, but from memory I had issues with either the optional or the throwing on Android. 138 | */ 139 | public struct JavaCallback { 140 | private let jobj: jobject // must be a JNI Global Reference 141 | private let methodID: jmethodID 142 | 143 | // Eventually we should check how many parameters are required by the method signature 144 | // And also which return type is expected (to allow calling non-Void methods) 145 | // For now this implementation remains unsafe 146 | //let expectedParameterCount: Int 147 | 148 | /// Errors describing the various things that can go wrong when calling a Java method via JNI. 149 | /// - __InvalidParameters__: One character per method parameter is required. For example, with a methodSignature of "(FF)V", you need to pass two floats as parameters. 150 | /// - __InvalidMethod__: Couldn't get the requested method from the jobject provided (are you calling with the right jobject instance / calling on the correct class?) 151 | /// - __IncorrectMethodSignature__: The JNI is separated into Java method calls to functions with various return types. So if you perform `callJavaMethod`, you need to accept the return value with the corresponding type. *XXX: currently only Void methods are implemented*. 152 | 153 | enum Error: ErrorType { 154 | case JNINotReady 155 | case InvalidParameters 156 | case IncorrectMethodSignature 157 | case InvalidClass 158 | case InvalidMethod 159 | } 160 | 161 | /** 162 | - Parameters: 163 | - globalJobj: The class instance you want to perform the method on. Note this must be a jni GlobalRef, otherwise your callback will either crash or just silently not work. 164 | - methodName: A `String` with the name of the Java method to call 165 | - methodSignature: A `String` containing the method's exact signature. Although it is possible to call non-Void Java methods via the JNI, that is not yet implemented in the the current Swift binding. This means that, for now, `methodSignature` must end with `"V"` i.e., return `Void` 166 | - **`"(F)V"`** would reference a method that accepts one Float and returns Void. 167 | - **Z** boolean 168 | - **B** byte 169 | - **C** char 170 | - **S** short 171 | - **I** int 172 | - **J** long 173 | - **F** float 174 | - **D** double 175 | - **Lfully-qualified-class;** fully-qualified-class 176 | - **[type** type[] 177 | - **(arg-types)ret-type** method type 178 | - e.g. **`"([I)V"`** would accept one array of Ints and return Void. 179 | - parameters: Any number of jvalues (*must have the same number and type as the* `methodSignature` *you're trying to call*) 180 | - Throws: `JavaCallback.Error` 181 | */ 182 | public init (_ globalJobj: jobject, methodName: String, methodSignature: String) { 183 | // At the moment we can only call Void methods, fail if user tries to return something else 184 | guard let returnType = methodSignature.characters.last where returnType == "V"/*oid*/ else { 185 | // LOG JavaMethodCallError.IncorrectMethodSignature 186 | fatalError("JavaMethodCallError.IncorrectMethodSignature") 187 | } 188 | 189 | // With signature "(FF)V", parameters count should be 2, ignoring the two brackets and the V 190 | // XXX: This test isn't robust, but it will prevent simple user errors 191 | // Doesn't work with more complex object types, arrays etc. we should determine the signature based on parameters. 192 | 193 | // TODO: Check methodSignature here and determine expectedParameterCount 194 | 195 | guard 196 | let javaClass = jni.GetObjectClass(globalJobj), 197 | let methodID = jni.GetMethodID(javaClass, methodName: methodName, methodSignature: methodSignature) 198 | else { 199 | // XXX: We should throw here and keep throwing til it gets back to Java 200 | fatalError("Failed to make JavaCallback") 201 | } 202 | 203 | self.jobj = globalJobj 204 | self.methodID = methodID 205 | } 206 | 207 | public func apply(args: [jvalue]) { 208 | jni.CallVoidMethodA(jobj, methodID: methodID, args: args) 209 | } 210 | 211 | /// Send variadic parameters to the func that takes an array 212 | public func call(args: jvalue...) { 213 | self.apply(args) 214 | } 215 | } 216 | 217 | -------------------------------------------------------------------------------- /module.map.in: -------------------------------------------------------------------------------- 1 | //===--- module.map -------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift.org open source project 4 | // 5 | // Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See http://swift.org/LICENSE.txt for license information 9 | // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | module CJNI [system] { 14 | header "@JNI_INCLUDE_PATH@/jni.h" 15 | export * 16 | } 17 | 18 | --------------------------------------------------------------------------------