Skip to content
This repository has been archived by the owner on Apr 29, 2024. It is now read-only.

Commit

Permalink
Most changes suggested in Review 1
Browse files Browse the repository at this point in the history
    * Use final_locals lint rule
    * Fix HelperNotFoundException breaking on flutter
    * Prevent memory leak in presence of exceptions
    * Documentation changes
    * Use inheritStdio in setup.dart
Hopefully most reviews are covered. There might be a few that I missed.

Thanks @liamappelbe and @dcharkes for very detailed reviews!
  • Loading branch information
mahesh-hegde committed Jul 14, 2022
1 parent dd7dfef commit ea680d5
Show file tree
Hide file tree
Showing 23 changed files with 793 additions and 562 deletions.
9 changes: 4 additions & 5 deletions jni/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,19 @@ This is intended for one-off / debugging uses of JNI, as well as providing a bas
__To interface a complete java library, look forward for `jni_gen`.__

## Platform support
The focus of this project is Android, since it already has a JVM and JNI allows interop with existing code and Platform APIs. Experimental desktop support exists for Linux using the JVM invocation API.
The focus of this project is Flutter Android, since Flutter Android apps already have a JVM, and JNI enables interop with existing Java code and Android Platform APIs. This project also (partially) supports Linux desktop by spawning a JVM through JNI.

## Version note
This library is at an early stage and the public API may rapidly change based on requirements of `jni_gen`.
This library is at an early stage of development and we do not provide backwards compatibility of the API at this point.

## Documentation

There are well-commented test files under `test/` directory and a flutter based example under `example/`.
The test/ directory contains files with comments explaining the basics of this module, and the example/ directory contains a flutter example which also touches some Android-specifics.

Using this library assumes some familiarity with JNI - it's threading model and object references, among other things.

## jni_gen

This library is a part of `jni_gen` - a 2022 GSoC project.

The broader aim of jni_gen is making Java APIs accessible from dart in an idiomatic way. The current focus is on the Android platform.
The broader aim of jni_gen is making Java APIs accessible from dart in an idiomatic way.

9 changes: 9 additions & 0 deletions jni/analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
include: package:flutter_lints/flutter.yaml

analyzer:
exclude: [build/**]
language:
strict-raw-types: true

linter:
rules:
- prefer_final_locals
- prefer_const_declarations
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options
11 changes: 6 additions & 5 deletions jni/bin/setup.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@ class CommandRunner {
String exec, List<String> args, String workingDir) async {
if (printCmds) {
final cmd = "$exec ${args.join(" ")}";
stderr.writeln("+ [$workingDir] $cmd");
stderr.writeln("\n+ [$workingDir] $cmd");
}
final process =
await Process.start(exec, args, workingDirectory: workingDir);
// stdout.addStream(process.stdout);
final process = await Process.start(exec, args,
workingDirectory: workingDir,
runInShell: Platform.isWindows,
mode: ProcessStartMode.inheritStdio);
final exitCode = await process.exitCode;
if (exitCode != 0) {
stderr.writeln("command exited with $exitCode");
Expand Down Expand Up @@ -107,7 +108,7 @@ void main(List<String> arguments) async {

Future<void> build(Options options, String srcPath, String buildPath) async {
final runner = CommandRunner(printCmds: true);
var cmakeArgs = [srcPath];
final cmakeArgs = [srcPath];
if (options.cmakeArgs != null) {
cmakeArgs.addAll(options.cmakeArgs!.split(" "));
}
Expand Down
7 changes: 7 additions & 0 deletions jni/example/analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@
# packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml

analyzer:
exclude: [build/**]
language:
strict-raw-types: true

linter:
# The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
Expand All @@ -22,6 +27,8 @@ linter:
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint.
rules:
- prefer_final_locals
- prefer_const_declarations
# avoid_print: false # Uncomment to disable the `avoid_print` rule
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule

Expand Down
29 changes: 15 additions & 14 deletions jni/example/integration_test/jni_object_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ void main() {
Jni.spawn();
}

var jni = Jni.getInstance();
final jni = Jni.getInstance();
testWidgets('get JNI Version', (tester) async {
final env = jni.getEnv();
expect(env.GetVersion(), isNot(equals(0)));
Expand Down Expand Up @@ -120,7 +120,8 @@ void main() {
for (int i = 0; i < 100; i++) {
int r = random.callIntMethod(nextIntMethod, [256 * 256]);
int bits = 0;
int jbc = longClass.callStaticIntMethod(bitCountMethod, [JValueLong(r)]);
final jbc =
longClass.callStaticIntMethod(bitCountMethod, [JValueLong(r)]);
while (r != 0) {
bits += r % 2;
r = (r / 2).floor();
Expand All @@ -133,13 +134,13 @@ void main() {
});

testWidgets("invoke_", (tester) async {
var m = jni.invokeLongMethod(
final m = jni.invokeLongMethod(
"java/lang/Long", "min", "(JJ)J", [JValueLong(1234), JValueLong(1324)]);
expect(m, equals(1234));
});

testWidgets("retrieve_", (tester) async {
var maxLong = jni.retrieveShortField("java/lang/Short", "MAX_VALUE", "S");
final maxLong = jni.retrieveShortField("java/lang/Short", "MAX_VALUE", "S");
expect(maxLong, equals(32767));
});

Expand All @@ -163,19 +164,19 @@ void main() {
});

testWidgets("Passing strings in arguments 2", (tester) async {
var twelve = jni.invokeByteMethod(
final twelve = jni.invokeByteMethod(
"java/lang/Byte", "parseByte", "(Ljava/lang/String;)B", ["12"]);
expect(twelve, equals(12));
});

testWidgets("use() method", (tester) async {
var randomInt = jni.newInstance("java/util/Random", "()V", []).use(
final randomInt = jni.newInstance("java/util/Random", "()V", []).use(
(random) => random.callIntMethodByName("nextInt", "(I)I", [15]));
expect(randomInt, lessThan(15));
});

testWidgets("enums", (tester) async {
var ordinal = jni
final ordinal = jni
.retrieveObjectField(
"java/net/Proxy\$Type", "HTTP", "Ljava/net/Proxy\$Type;")
.use((f) => f.callIntMethodByName("ordinal", "()I", []));
Expand All @@ -187,14 +188,14 @@ void main() {
});

testWidgets("JniGlobalRef", (tester) async {
var uri = jni.invokeObjectMethod(
final uri = jni.invokeObjectMethod(
"java/net/URI",
"create",
"(Ljava/lang/String;)Ljava/net/URI;",
["https://www.google.com/search"]);
var rg = uri.getGlobalRef();
final rg = uri.getGlobalRef();
await Future.delayed(const Duration(seconds: 1), () {
var env = jni.getEnv();
final env = jni.getEnv();
// Now comment this line & try to directly use uri local ref
// in outer scope.
//
Expand All @@ -203,8 +204,8 @@ void main() {
//
// Therefore, don't share JniObjects across functions that can be
// scheduled across threads, including async callbacks.
var uri = JniObject.fromGlobalRef(env, rg);
var scheme =
final uri = JniObject.fromGlobalRef(env, rg);
final scheme =
uri.callStringMethodByName("getScheme", "()Ljava/lang/String;", []);
expect(scheme, "https");
uri.delete();
Expand All @@ -215,8 +216,8 @@ void main() {
}

void doSomeWorkInIsolate(Void? _) {
var jni = Jni.getInstance();
var random = jni.newInstance("java/util/Random", "()V", []);
final jni = Jni.getInstance();
final random = jni.newInstance("java/util/Random", "()V", []);
// var r = random.callIntMethodByName("nextInt", "(I)I", [256]);
// expect(r, lessThan(256));
// Expect throws an OutsideTestException
Expand Down
2 changes: 1 addition & 1 deletion jni/example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ class _ExampleCardState extends State<ExampleCard> {

@override
Widget build(BuildContext context) {
var eg = widget.example;
final eg = widget.example;
var result = "";
var hasError = false;
if (_run) {
Expand Down
7 changes: 7 additions & 0 deletions jni/example/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.11"
args:
dependency: transitive
description:
name: args
url: "https://pub.dartlang.org"
source: hosted
version: "2.3.1"
async:
dependency: transitive
description:
Expand Down
2 changes: 1 addition & 1 deletion jni/example/test/widget_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ void main() {
if (!Platform.isAndroid) {
Jni.spawn(helperDir: "../src/build");
}
var jni = Jni.getInstance();
final jni = Jni.getInstance();
testWidgets("simple toString example", (tester) async {
await tester.pumpWidget(ExampleForTest(ExampleCard(Example(
"toString",
Expand Down

0 comments on commit ea680d5

Please sign in to comment.