You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: pkgs/jnigen/README.md
+40-72Lines changed: 40 additions & 72 deletions
Original file line number
Diff line number
Diff line change
@@ -6,24 +6,20 @@
6
6
## Introduction
7
7
Experimental bindings generator for Java bindings through dart:ffi and JNI.
8
8
9
-
`jnigen` scans compiled JAR files or Java source code to generate a description of the API, then uses it to generate Dart annd C bindings. The Dart bindings call the C bindings, which in-turn call the Java functions through JNI. Shared functionality and base classes are provided through the support library, `package:jni`.
9
+
`jnigen` scans compiled JAR files or Java source code to generate a description of the API, then uses it to generate Dart bindings. The Dart bindings call the C bindings, which in-turn call the Java functions through JNI. Shared functionality and base classes are provided through the support library, `package:jni`.
10
10
11
11
The configuration for binding generation is usually provided through YAML.
12
12
13
13
Three configuration details are needed to generate the bindings. Everything else is optional:
14
14
15
15
*_Inputs_: input can be Java source files (`source_path`), or compiled classes / JARs (`class_path`). Some maven / gradle based tooling is also provided to simplify obtaining dependencies.
16
16
17
-
*_Outputs_: Output can be generated in package-structured (one file per class) or single file bindings. Target path to write C and Dart bindings needs to be specified.
17
+
*_Outputs_: Output can be generated in package-structured (one file per class) or single file bindings. Target path to write Dart bindings needs to be specified.
18
18
19
19
*_Classes_: Specify which classes or packages you need bindings for. Specifying a package includes all classes inside it recursively.
20
20
21
21
Check out the [examples](jnigen/example/) to see some sample configurations.
22
22
23
-
C code is always generated into a directory with it's own build configuration. It's built as a separate dynamic library.
24
-
25
-
Lastly, [dart_only bindings](#pure-dart-bindings) mode is also available as a proof-of-concept. It does not need intermediate C bindings, only a dependency on the support library `package:jni`.
26
-
27
23
## Example
28
24
It's possible to generate bindings for JAR libraries, or Java source files.
29
25
@@ -53,53 +49,50 @@ This produces the following boilerplate:
53
49
54
50
```dart
55
51
/// Some boilerplate is omitted for clarity.
56
-
final ffi.Pointer<T> Function<T extends ffi.NativeType>(String sym) jniLookup =
@@ -145,8 +135,6 @@ More advanced features such as callbacks are not supported yet. Support for thes
145
135
146
136
On Flutter targets, native libraries are built automatically and bundled. On standalone platforms, no such infrastructure exists yet. As a stopgap solution, running `dart run jni:setup` in a target directory builds all JNI native dependencies of the package into `build/jni_libs`.
147
137
148
-
By default `jni:setup` goes through pubspec configuration and builds all JNI dependencies of the project. It can be overridden to build a custom directory using `-s` switch, which can be useful when output configuration for C bindings does not follow standard FFI plugin layout.
149
-
150
138
The build directory has to be passed to `Jni.spawn` call. It's assumed that all dependencies are built into the same target directory, so that once JNI is initialized, generated bindings can load their respective C libraries automatically.
If JAVA_HOME not set, find the `java.exe` executable and set the environment variable in Control Panel. If java is installed through a package manager, there may be a more automatic way to do this. (Eg: `scoop reset`).
173
161
174
-
### C/C++ tooling
175
-
CMake and a standard C toolchain are required to build `package:jni` and C bindings generated by `jnigen`.
176
-
177
-
It's recommended to have `clang-format` installed for formatting the generated C bindings. On Windows, it's part of LLVM installation. On most Linux distributions it is available as a separate package. On MacOS, it can be installed using Homebrew.
162
+
### C tooling
163
+
CMake and a standard C toolchain are required to build `package:jni`.
178
164
179
165
## FAQs
180
166
@@ -225,11 +211,6 @@ A `*` denotes required configuration.
225
211
| `classes` * | List of qualified class / package names | List of qualified class / package names. `source_path` will be scanned assuming the sources follow standard java-ish hierarchy. That is a.b.c either maps to a directory `a/b/c` or a class file `a/b/c.java`. |
226
212
| `enable_experiment` | List of experiment names:<br><ul><li>`interface_implementation`</li></ul> | List of enabled experiments. These features are still in development and their API might break. |
227
213
| `output:` | (Subsection) | This subsection will contain configuration related to output files. |
228
-
|`output:` >> `bindings_type`|`c_based` (default) or `dart_only`| Binding generation strategy. [Trade-offs](#pure-dart-bindings) are explained at the end of this document. |
229
-
|`output:` >> `c:`| (Subsection) | This subsection specified C output configuration. Required if `bindings_type` is `c_based`. |
230
-
|`output:` >> `c:` >> path * | Directory path | Directory to write C bindings. Usually `src/` in case of an FFI plugin template. |
231
-
|`output:` >> `c:` >> subdir | Directory path | If specified, C bindings will be written to `subdir` resolved relative to `path`. This is useful when bindings are supposed to be under source's license, and written to a subdirectory such as `third_party`. |
232
-
| `output:` >> `c:` >> `library_name`*| Identifier (snake_case) | Name for generated C library.
| `output:` >> `dart:` >> `structure` | `package_structure` / `single_file` | Whether to map resulting dart bindings to file-per-class source layout, or write all bindings to single file.
235
216
| `output:` >> `dart:` >> `path` * | Directory path or File path | Path to write Dart bindings. Should end in `.dart` for `single_file` configurations, and end in `/` for `package_structure` (default) configuration. |
@@ -255,19 +236,6 @@ It's possible to use the programmatic API instead of YAML.
255
236
* import `package:jnigen/jnigen.dart`
256
237
* construct a `Config` object and pass it to `generateJniBindings` function. The parameters are similar to the ones described above.
257
238
258
-
## Pure dart Bindings
259
-
It's possible to generate bindings that do not rely on an intermediate layer of C code. Bindings will still depend on `package:jni` and its support library written in C. But this approach avoids large C bindings.
260
-
261
-
To enable pure dart bindings, specify
262
-
```
263
-
output:
264
-
bindings_type: dart_only
265
-
```
266
-
267
-
Any C output configuration will be ignored.
268
-
269
-
However, pure dart bindings will require additional allocations and check runtimeType of the arguments. This will be the case until Variadic arguments land in Dart FFI.
270
-
271
239
## Android core libraries
272
240
These days, Android projects depend heavily on AndroidX and other libraries downloaded via gradle. We have a tracking issue to improve detection of android SDK and dependencies. (#31). Currently we can fetch the JAR dependencies of an android project, by running a gradle stub, if `android_sdk_config` >> `add_gradle_deps` is specified.
This example shows how to write custom java code in `android/app/src` and call it using `jnigen` generated bindings.
3
+
This example shows how to write custom java code in `android/app/src` and call
4
+
it using `jnigen` generated bindings.
4
5
5
6
#### How to run this example:
6
-
* Run `flutter run` to run the app.
7
7
8
-
* To regenerate bindings after changing Java code, run `flutter pub run jnigen --config jnigen.yaml`. This requires at least one APK build to have been run before, so that it's possible for `jnigen` to obtain classpaths of Android Gradle libraries. Therefore, once run `flutter build apk` before generating bindings for the first time, or after a `flutter clean`.
8
+
- Run `flutter run`to run the app.
9
9
10
-
#### General steps
11
-
These are general steps to integrate Java code into a flutter project using `jnigen`.
12
-
13
-
* Write Java code in suitable package folder, under `android/` subproject of the flutter app.
14
-
15
-
* Create A jnigen config like `jnigen.yaml` in this example.
10
+
- To regenerate bindings after changing Java code, run
11
+
`flutter pub run jnigen --config jnigen.yaml`. This requires at least one APK
12
+
build to have been run before, so that it's possible for `jnigen` to obtain
13
+
classpaths of Android Gradle libraries. Therefore, once run
14
+
`flutter build apk` before generating bindings for the first time, or after a
15
+
`flutter clean`.
16
16
17
-
* Generate bindings using jnigen config.
18
-
19
-
* Add an `externalNativeBuild` to gradle script (see `android/app/build.gradle` in this example).
20
-
21
-
* Add proguard rules to exclude your custom classes from tree shaking, since they are always accessed reflectively in JNI.
17
+
#### General steps
22
18
23
-
* Build and run the app.
19
+
These are general steps to integrate Java code into a flutter project using
20
+
`jnigen`.
24
21
22
+
- Write Java code in suitable package folder, under `android/` subproject of the
23
+
flutter app.
24
+
- Create A jnigen config like `jnigen.yaml` in this example.
25
+
- Generate bindings using jnigen config.
26
+
- Add proguard rules to exclude your custom classes from tree shaking, since
0 commit comments