Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Write & call Swift code using Java’s JNI

As you see here one can perform native C/C++ method calls from Java code, thanks to JVM’s JNI. But how about performing calls of Swift methods? Is this possible or going to be possible (can be implemented in a reasonable time frame) as Swift becomes more popular?

I want to access Apple’s native API that is only accessible when one writes apps in either Objective-C or Swift. As the JVM is just being ported to ARMv8 (64-bit), I could also imagine the JVM as an alternative runtime for iOS apps in the future. But this might be the future... The present is: The JVM runs on Mac OS X and one can write apps for Mac OS X in Swift that can access some APIs that might be not accessible to Java apps in the same way.

like image 242
Alex Avatar asked Dec 23 '14 21:12

Alex


People also ask

Is it Wright or write?

Wright is a skilled worker (usually a maker or builder), such as a shipwright, wheelwright, or playwright. Write is a verb that means to form characters (letters, words, pictures) on a surface (paper, screen, wall) with an instrument (pen, keyboard, fingers).

What do you mean of write?

transitive verb. 1a : to form (characters, symbols, etc.) on a surface with an instrument (such as a pen) b : to form (words) by inscribing characters or symbols on a surface write one's name. c : to spell in writing words written alike but pronounced differently.

What is write in writing?

/ (raɪt) / verb writes, writing, wrote or written. to draw or mark (symbols, words, etc) on a surface, usually paper, with a pen, pencil, or other instrument. to describe or record (ideas, experiences, etc) in writing. to compose (a letter) to or correspond regularly with (a person, organization, etc)

Is there a word write?

Write is the modern day spelling of the Old English writan, meaning “to score, outline, draw the figure of.” Now it has the sense of “to set down in writing.” You can write music, a short story, or computer code. You can write a letter, or write in cursive.


1 Answers

Well, roughly 5½ years later, it turned out, it wasn't the future... No JVMs on iOS.

But you can definitely do it, i.e., call Swift APIs from Java. That said, it's quite cumbersome, because AFAIK, you have to take a detour via C/C++.

Here's the deal:

  • As you know, you can use JNI to call C code.
  • From C you can call Swift.

The following relies heavily on this question.

Code

Your Java code is in helloworld/SwiftHelloWorld.java:

package helloworld;

public class SwiftHelloWorld {

    static {
        System.loadLibrary("SwiftHelloWorld");
    }

    public static native void printHelloWorldImpl();

    public static void main(final String[] args) {
        printHelloWorldImpl();
    }

}

Now write the native C code (file helloworld_SwiftHelloWorld.c):

#include <jni.h>
#include <stdio.h>
#include "helloworld_SwiftHelloWorld.h"
#include "helloworld_SwiftHelloWorld_swift.h"

JNIEXPORT void JNICALL Java_helloworld_SwiftHelloWorld_printHelloWorldImpl
  (JNIEnv *env, jclass clazz) {

    int result = swiftHelloWorld(42);
    printf("%s%i%s", "Hello World from JNI! ", result, "\n");

}

Which uses a header file named helloworld_SwiftHelloWorld_swift.h for our (yet to be written) Swift code:

int swiftHelloWorld(int);

Finally, our Swift code resides in SwiftCode.swift:

import Foundation

// force the function to have a name callable by the c code
@_silgen_name("swiftHelloWorld")
public func swiftHelloWorld(number: Int) -> Int {
    print("Hello world from Swift: \(number)")
    return 69
}

Building

To build all this, we first have to compile the Swift code to a dynamic library:

swiftc SwiftCode.swift -emit-library -o libSwiftCode.dylib -Xlinker -install_name -Xlinker libSwiftCode.dylib

We use the -Xlinker directives to ensure that the dylib's location is relative.

Before we can create the C dylib, we first have to generate the Java headers:

javac -h . helloworld/SwiftHelloWorld.java

Now that we have the Java headers and the Swift dylib, we can compile the C dylib, which links against the Swift dylib:

gcc -I"$JAVA_HOME/include" -I"$JAVA_HOME/include/darwin/" -o libSwiftHelloWorld.dylib -dynamiclib helloworld_SwiftHelloWorld.c libSwiftCode.dylib

Now that everything is in place, we must make sure that both dylibs are in the same directory and that that directory can be found by Java, i.e., you may need to set -Djava.library.path=<dir of your dylibs>.

Et voilà!

Swift called from Java!

like image 171
Hendrik Avatar answered Oct 14 '22 13:10

Hendrik