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

Add jni #9

Closed
wants to merge 23 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions .github/workflows/test-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,35 @@ jobs:
github-token: ${{ secrets.GITHUB_TOKEN }}
path-to-lcov: ./jni_gen/coverage/lcov.info

test_jni:
runs-on: ${{ matrix.os }}
defaults:
run:
working-directory: ./jni
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
steps:
- uses: actions/checkout@v3
- uses: subosito/flutter-action@v2
with:
channel: 'stable'
- uses: actions/setup-java@v2
with:
distribution: 'zulu'
java-version: '11'
- run: |
mkdir build
cd build
cmake .. && cmake --build .
working-directory: ./jni/src
- run: flutter pub get
- run: flutter format --output=none --set-exit-if-changed .
- run: flutter analyze --fatal-infos
- run: dart pub get
- run: dart test

build_jni_example_linux:
runs-on: ubuntu-latest
defaults:
Expand All @@ -84,11 +113,23 @@ jobs:
- uses: subosito/flutter-action@v2
with:
channel: 'stable'
- uses: actions/setup-java@v2
with:
distribution: 'zulu'
java-version: '11'
- run: |
sudo apt-get update -y
sudo apt-get install -y ninja-build libgtk-3-dev
- run: |
cd ../src/
mkdir build
cd build
cmake .. && cmake --build .
cd ../../example
- run: flutter config --enable-linux-desktop
- run: flutter pub get
- run: flutter test
- run: flutter test integration_test/integration_test.dart -d linux
- run: flutter build linux

build_jni_example_windows:
Expand All @@ -101,8 +142,13 @@ jobs:
- uses: subosito/flutter-action@v2
with:
channel: 'stable'
- uses: actions/setup-java@v2
with:
distribution: 'zulu'
java-version: '11'
- run: flutter config --enable-windows-desktop
- run: flutter pub get
- run: flutter test integration_test/integration_test.dart -d windows
- run: flutter build windows

build_jni_example_macos:
Expand All @@ -116,6 +162,10 @@ jobs:
with:
channel: 'stable'
architecture: x64
- uses: actions/setup-java@v2
with:
distribution: 'zulu'
java-version: '11'
- run: flutter config --enable-macos-desktop
- run: flutter pub get
- run: flutter build macos
Expand Down
61 changes: 61 additions & 0 deletions jni/android/src/main/java/dev/dart/jni/JniPlugin.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package dev.dart.jni;

import androidx.annotation.Keep;
import androidx.annotation.NonNull;
import android.util.Log;
import android.app.Activity;
import io.flutter.plugin.common.PluginRegistry.Registrar;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.embedding.engine.plugins.activity.ActivityAware;
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;

import android.content.Context;

@Keep
public class JniPlugin implements FlutterPlugin, ActivityAware {

@Override
public void
onAttachedToEngine(@NonNull FlutterPluginBinding binding) {
setup(binding.getApplicationContext());
}

public static void registerWith(Registrar registrar) {
JniPlugin plugin = new JniPlugin();
plugin.setup(registrar.activeContext());
}

private void setup(Context context) {
initializeJni(context, getClass().getClassLoader());
}

@Override
public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {}

// Activity handling methods
@Override
public void onAttachedToActivity(@NonNull ActivityPluginBinding binding) {
Activity activity = binding.getActivity();
setJniActivity(activity, activity.getApplicationContext());
}

@Override
public void onDetachedFromActivityForConfigChanges() {}

@Override
public void onReattachedToActivityForConfigChanges(@NonNull ActivityPluginBinding binding) {
Activity activity = binding.getActivity();
setJniActivity(activity, activity.getApplicationContext());
}

@Override
public void onDetachedFromActivity() {}

native void initializeJni(Context context, ClassLoader classLoader);
native void setJniActivity(Activity activity, Context context);

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package dev.dart.jni_example;

import android.app.Activity;
import android.os.Handler;
import android.content.Context;
import android.widget.Toast;
import androidx.annotation.Keep;

@Keep
class AnyToast {
static AnyToast makeText(Activity mainActivity, Context context, CharSequence text, int duration) {
AnyToast toast = new AnyToast();
toast.mainActivity = mainActivity;
toast.context = context;
toast.text = text;
toast.duration = duration;
return toast;
}

void show() {
mainActivity.runOnUiThread(() -> Toast.makeText(context, text, duration).show());
}

Activity mainActivity;
Context context;
CharSequence text;
int duration;
}
39 changes: 39 additions & 0 deletions jni/example/integration_test/integration_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import 'dart:io';
// import 'package:path/path.dart' as path;
import 'package:ffi/ffi.dart';

import 'package:flutter_test/flutter_test.dart';

import 'package:jni/jni.dart';

void main() {
if (!Platform.isAndroid) {
Jni.spawn();
}

var jni = Jni.getInstance();

testWidgets('Manually lookup & call Long.toHexString static method',
(tester) async {
final arena = Arena();
final env = jni.getEnv();

final longClass = env.FindClass("java/lang/Long".toNativeChars(arena));
final hexMethod = env.GetStaticMethodID(
longClass,
"toHexString".toNativeChars(arena),
"(J)Ljava/lang/String;".toNativeChars(arena));

for (var i in [1, 80, 13, 76, 1134453224145]) {
final jres = env.CallStaticObjectMethodA(
longClass, hexMethod, Jni.jvalues([JValueLong(i)], allocator: arena));

final res = env.asDartString(jres);
expect(res, equals(i.toRadixString(16)));

env.DeleteLocalRef(jres);
}
env.DeleteLocalRef(longClass);
arena.releaseAll();
});
}
Loading