Cross-cutting aspects to make it easy for Flutter apps to interact with Android APIs
- Dominant language
- Dart
- Stars
- 275
- Forks
- 144
- Avg merge
- 2d 10h
- Merged PRs (30d)
- 47
Description
Our `package:jnigen`s purpose is to produce dart bindings for Java/Kotlin APIs based on `.jar` files or java/kotlin sources. That is useful in general - but our main motivation for building this is to allow easy interop with Java/Kotlin APIs **on Android** in the context of Flutter.
There are some specifics to this that we should keep in mind:
### Thread restricted APIs
Certain Android APIs are only usable from the platform UI thread or worker threads. The APIs may indicate that via a [@UiThread](https://developer.android.com/reference/androidx/annotation/UiThread) or [@WorkerThread](https://developer.android.com/reference/androidx/annotation/WorkerThread) annotation.
Once we have a mechanism to run code on the platform UI thread, the bindings generator could take advantage of that mechanism (e.g. by producing asynchronous `Future`-based APIs that perform the actual call on the platform thread)
### APIs requiring Context / Activity / ... objects
Certain Android APIs require callers to pass along special objects. Among them e.g. [android.content.Context](https://developer.android.com/reference/android/content/Context) objects. There's different kinds of context objects (most importantly: application context, activity contexts, service contexts). Those special objects have lifecycles during which they can be used (e.g. while an activity is active).
Flutter code (on UI isolate or background isolate) that wishes to invoke Android APIs may need access to such special objects. We'll probably need a way to obtain those and expose them to Dart so they can be used when invoking the generated Android API bindings. This may require integration into flutter engine and/or making a flutter-plugin with method channels that exposes them.
Normal Flutter apps are structured in the following way: The application code extends `FlutterActivity`. Once the activitie's `onCreate()` lifecycle method is invoked, it will create a `FlutterEngine` object with the activity context. Once plugins are attached to an engine, they will get notified when the engine gets attached/detached to/from activities/services/... The plugins do have - in those lifecycle callbacks - access to e.g. context / activity objects.
We should also think about whether there can be possible races happening in the lifecycle of those objects and the usage of those from Dart.
### Testing
Given the nature of method channels - which are similar to e.g. gRPC (i.e. generated message classes and RPC stubs) - one could mock the native side using Dart code rather easily - which may be amenable to unit tests. We should think about how using direct interop with native impacts testability of code.
/cc @HosseinYousefi
Contributor guide
Assessment
This issue has not been assessed yet.