diff --git a/.github/workflows/test-package.yml b/.github/workflows/test-package.yml index a48cd8b..7eed76e 100644 --- a/.github/workflows/test-package.yml +++ b/.github/workflows/test-package.yml @@ -82,3 +82,67 @@ jobs: - run: dart pub upgrade - run: dart run wasm:setup - run: dart test + + flutter_analyze: + runs-on: ubuntu-latest + defaults: + run: + working-directory: flutter_wasm + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-java@v1 + with: + java-version: '12.x' + - uses: subosito/flutter-action@v1.5.3 + with: + flutter-version: '2.5.0' + - id: install + run: | + flutter pub upgrade + flutter pub upgrade --directory example + - run: flutter format --output=none --set-exit-if-changed . + if: always() && steps.install.outcome == 'success' + - run: flutter analyze --fatal-infos + if: always() && steps.install.outcome == 'success' + + flutter_test: + runs-on: ubuntu-latest + defaults: + run: + working-directory: flutter_wasm + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-java@v1 + with: + java-version: '12.x' + - uses: subosito/flutter-action@v1.5.3 + with: + flutter-version: '2.5.0' + - run: flutter pub upgrade + - run: flutter pub run wasm:setup + - run: flutter test + + flutter_example_test: + runs-on: ubuntu-latest + defaults: + run: + working-directory: flutter_wasm/example + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-java@v1 + with: + java-version: '12.x' + - uses: android-actions/setup-android@v2.0.2 + - uses: nttld/setup-ndk@v1 + with: + ndk-version: r21e + add-to-path: true + - run: echo "ndk.dir=$(dirname $(which ndk-build))" >> android/local.properties + - uses: subosito/flutter-action@v1.5.3 + with: + flutter-version: '2.5.0' + - run: flutter pub upgrade + - run: flutter pub run wasm:setup + - run: flutter test + - run: flutter build apk + - run: flutter build appbundle diff --git a/README.md b/README.md index 57224a6..ac26073 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,6 @@ These packages provide utilities for loading and running WASM modules. Runs WASM modules in Dart native. -## flutter_wasm (coming soon) +## [flutter_wasm](https://github.com/dart-lang/wasm/blob/main/flutter_wasm/README.md) Runs WASM modules in Flutter. diff --git a/flutter_wasm/.gitignore b/flutter_wasm/.gitignore new file mode 100644 index 0000000..9be145f --- /dev/null +++ b/flutter_wasm/.gitignore @@ -0,0 +1,29 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. +/pubspec.lock +**/doc/api/ +.dart_tool/ +.packages +build/ diff --git a/flutter_wasm/.metadata b/flutter_wasm/.metadata new file mode 100644 index 0000000..64df19a --- /dev/null +++ b/flutter_wasm/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: d5396898bed65dacfb355fb6e52ec7ccf76746d9 + channel: unknown + +project_type: plugin diff --git a/flutter_wasm/CHANGELOG.md b/flutter_wasm/CHANGELOG.md new file mode 100644 index 0000000..e52cf09 --- /dev/null +++ b/flutter_wasm/CHANGELOG.md @@ -0,0 +1,3 @@ +## 0.0.1 + +- Initial version diff --git a/flutter_wasm/README.md b/flutter_wasm/README.md new file mode 100644 index 0000000..3a2be10 --- /dev/null +++ b/flutter_wasm/README.md @@ -0,0 +1,22 @@ +Provides utilities for loading and running WASM modules in Flutter apps. +Currently only Android is supported. + +This is a wrapper around [package:wasm](https://github.com/dart-lang/wasm/blob/main/wasm/README.md). +See that package for more information and documentation. The basic +usage is mostly the same as in that package. The main thing this plugin does is +run `wasm:setup` for your target device during app compilation. + +## Usage + +1. Add a dependency to *both* package `wasm` and `flutter_wasm` in +`pubspec.yaml` and run `flutter pub get`. [#52](https://github.com/dart-lang/wasm/issues/52) + +1. Next run `flutter run wasm:setup` to build the Wasmer runtime for your host +machine. This does not build the runtime for your target device. It will take a +few minutes. + +1. Load your wasm code in your app. See the [example app](https://github.com/dart-lang/wasm/blob/main/flutter_wasm/example/lib/main.dart). + +1. Run your app using `flutter run`. If you see an error at runtime saying +"libwasmer.so not found", just try rebuiling. The first build sometimes fails. +[#51](https://github.com/dart-lang/wasm/issues/51) diff --git a/flutter_wasm/android/.gitignore b/flutter_wasm/android/.gitignore new file mode 100644 index 0000000..c6cbe56 --- /dev/null +++ b/flutter_wasm/android/.gitignore @@ -0,0 +1,8 @@ +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures diff --git a/flutter_wasm/android/build.gradle b/flutter_wasm/android/build.gradle new file mode 100644 index 0000000..d4b5aed --- /dev/null +++ b/flutter_wasm/android/build.gradle @@ -0,0 +1,128 @@ +// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +group 'dev.dart.flutter_wasm' +version '1.0-SNAPSHOT' + +import org.gradle.nativeplatform.platform.internal.DefaultNativePlatform + +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + mavenCentral() + } + + dependencies { + classpath 'com.android.tools.build:gradle:4.1.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +rootProject.allprojects { + repositories { + google() + mavenCentral() + } +} + +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' + +android { + compileSdkVersion 30 + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = '1.8' + } + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + defaultConfig { + minSdkVersion 16 + } + + def hostOs = DefaultNativePlatform.currentOperatingSystem.getName().toLowerCase() + def hostArch = DefaultNativePlatform.currentArchitecture.getName().replaceAll('-', '_') + def ndkBinDir = "${android.ndkDirectory}/toolchains/llvm/prebuilt/${hostOs}-${hostArch}/bin" + def projectProperties = new Properties() + projectProperties.load(project.rootProject.file('local.properties').newDataInputStream()) + def flutterDir = projectProperties.getProperty('flutter.sdk') + def platformVersion = -1 + fileTree("${android.ndkDirectory}/platforms").visit { FileVisitDetails details -> + if (details.isDirectory() && details.name.startsWith("android-")) { + platformVersion = Math.max(platformVersion, details.name.substring(8) as int) + } + } + if (platformVersion < 0) { + throw new Exception("Can't find any valid platforms in ${android.ndkDirectory}/platforms") + } + + tasks.register('wasm-pub-get') { + doLast { + exec { + workingDir '..' + commandLine "${flutterDir}/bin/flutter", 'pub', 'get' + } + } + } + + def architectures = [ + ['arm64-v8a', 'aarch64-linux-android', 'aarch64-linux-android', 'aarch64-linux-android', 'arch-arm64'], + ['x86', 'i686-linux-android', 'i686-linux-android', 'i686-linux-android', 'arch-x86'], + + // TODO(#53,#54): Enable these when they're supported by Wasmer. + // ['armeabi-v7a', 'armv7a-linux-androideabi', 'arm-linux-androideabi', 'armv7-linux-androideabi', 'arch-arm'], + // ['x86_64', 'x86_64-linux-android', 'x86_64-linux-android', 'x86_64-linux-android', 'arch-x86_64'], + ] + for (arch in architectures) { + def abi = arch[0] + def clangPrefix = "${arch[1]}${platformVersion}" + def arPrefix = arch[2] + def rustTriple = arch[3] + def sysroot = arch[4] + def sysrootDir = "${android.ndkDirectory}/platforms/android-${platformVersion}/${sysroot}" + def outDir = "${rootDir}/../build/app/intermediates/stripped_native_libs/debug/out/lib/${abi}/" + + tasks.register("wasm-lib-${abi}") { + // Specify inputs and outputs so that incremental build works properly. + inputs.property('platformVersion', platformVersion) + inputs.property('abi', abi) + outputs.file("${outDir}/libwasmer.so") + + dependsOn('wasm-pub-get') + + doLast { + exec { + workingDir '..' + commandLine "${flutterDir}/bin/flutter", 'pub', 'run', 'wasm:setup', + '--sysroot', sysrootDir, + '--target', rustTriple, + '--clang', "${ndkBinDir}/${clangPrefix}-clang", + '--clangpp', "${ndkBinDir}/${clangPrefix}-clang++", + '--ar', "${ndkBinDir}/${arPrefix}-ar", + '-o', outDir + } + } + } + } + + tasks.withType(JavaCompile) { compileTask -> + for (arch in architectures) { + def abi = arch[0] + compileTask.dependsOn("wasm-lib-${abi}") + } + } +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/flutter_wasm/android/settings.gradle b/flutter_wasm/android/settings.gradle new file mode 100644 index 0000000..b63c7d2 --- /dev/null +++ b/flutter_wasm/android/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'flutter_wasm' diff --git a/flutter_wasm/android/src/main/AndroidManifest.xml b/flutter_wasm/android/src/main/AndroidManifest.xml new file mode 100644 index 0000000..4a91b0b --- /dev/null +++ b/flutter_wasm/android/src/main/AndroidManifest.xml @@ -0,0 +1,3 @@ + + diff --git a/flutter_wasm/android/src/main/kotlin/dev/dart/flutter_wasm/FlutterWasmPlugin.kt b/flutter_wasm/android/src/main/kotlin/dev/dart/flutter_wasm/FlutterWasmPlugin.kt new file mode 100644 index 0000000..6795d5a --- /dev/null +++ b/flutter_wasm/android/src/main/kotlin/dev/dart/flutter_wasm/FlutterWasmPlugin.kt @@ -0,0 +1,15 @@ +// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +package dev.dart.flutter_wasm + +import androidx.annotation.NonNull + +import io.flutter.embedding.engine.plugins.FlutterPlugin + +/** FlutterWasmPlugin */ +class FlutterWasmPlugin: FlutterPlugin { + override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {} + override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {} +} diff --git a/flutter_wasm/example/.gitignore b/flutter_wasm/example/.gitignore new file mode 100644 index 0000000..0fa6b67 --- /dev/null +++ b/flutter_wasm/example/.gitignore @@ -0,0 +1,46 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/flutter_wasm/example/.metadata b/flutter_wasm/example/.metadata new file mode 100644 index 0000000..7adad5d --- /dev/null +++ b/flutter_wasm/example/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: d5396898bed65dacfb355fb6e52ec7ccf76746d9 + channel: unknown + +project_type: app diff --git a/flutter_wasm/example/README.md b/flutter_wasm/example/README.md new file mode 100644 index 0000000..ab51efe --- /dev/null +++ b/flutter_wasm/example/README.md @@ -0,0 +1,16 @@ +# flutter_wasm_example + +Demonstrates how to use the flutter_wasm plugin. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/flutter_wasm/example/android/.gitignore b/flutter_wasm/example/android/.gitignore new file mode 100644 index 0000000..6f56801 --- /dev/null +++ b/flutter_wasm/example/android/.gitignore @@ -0,0 +1,13 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java + +# Remember to never publicly share your keystore. +# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +key.properties +**/*.keystore +**/*.jks diff --git a/flutter_wasm/example/android/app/build.gradle b/flutter_wasm/example/android/app/build.gradle new file mode 100644 index 0000000..72c888d --- /dev/null +++ b/flutter_wasm/example/android/app/build.gradle @@ -0,0 +1,68 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 30 + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = '1.8' + } + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "dev.dart.flutter_wasm_example" + minSdkVersion 16 + targetSdkVersion 30 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig signingConfigs.debug + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/flutter_wasm/example/android/app/src/debug/AndroidManifest.xml b/flutter_wasm/example/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..57969cf --- /dev/null +++ b/flutter_wasm/example/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/flutter_wasm/example/android/app/src/main/AndroidManifest.xml b/flutter_wasm/example/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..a302f7b --- /dev/null +++ b/flutter_wasm/example/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + diff --git a/flutter_wasm/example/android/app/src/main/kotlin/com/example/flutter_wasm_example/MainActivity.kt b/flutter_wasm/example/android/app/src/main/kotlin/com/example/flutter_wasm_example/MainActivity.kt new file mode 100644 index 0000000..1dac50d --- /dev/null +++ b/flutter_wasm/example/android/app/src/main/kotlin/com/example/flutter_wasm_example/MainActivity.kt @@ -0,0 +1,10 @@ +// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +package dev.dart.flutter_wasm_example + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} diff --git a/flutter_wasm/example/android/app/src/main/res/drawable-v21/launch_background.xml b/flutter_wasm/example/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 0000000..f74085f --- /dev/null +++ b/flutter_wasm/example/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/flutter_wasm/example/android/app/src/main/res/drawable/launch_background.xml b/flutter_wasm/example/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 0000000..304732f --- /dev/null +++ b/flutter_wasm/example/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/flutter_wasm/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/flutter_wasm/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..db77bb4 Binary files /dev/null and b/flutter_wasm/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/flutter_wasm/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/flutter_wasm/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..17987b7 Binary files /dev/null and b/flutter_wasm/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/flutter_wasm/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/flutter_wasm/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..09d4391 Binary files /dev/null and b/flutter_wasm/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/flutter_wasm/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/flutter_wasm/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..d5f1c8d Binary files /dev/null and b/flutter_wasm/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/flutter_wasm/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/flutter_wasm/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..4d6372e Binary files /dev/null and b/flutter_wasm/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/flutter_wasm/example/android/app/src/main/res/values-night/styles.xml b/flutter_wasm/example/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 0000000..449a9f9 --- /dev/null +++ b/flutter_wasm/example/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/flutter_wasm/example/android/app/src/main/res/values/styles.xml b/flutter_wasm/example/android/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..d74aa35 --- /dev/null +++ b/flutter_wasm/example/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/flutter_wasm/example/android/app/src/profile/AndroidManifest.xml b/flutter_wasm/example/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..57969cf --- /dev/null +++ b/flutter_wasm/example/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/flutter_wasm/example/android/build.gradle b/flutter_wasm/example/android/build.gradle new file mode 100644 index 0000000..ed45c65 --- /dev/null +++ b/flutter_wasm/example/android/build.gradle @@ -0,0 +1,29 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + mavenCentral() + } + + dependencies { + classpath 'com.android.tools.build:gradle:4.1.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + mavenCentral() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/flutter_wasm/example/android/gradle.properties b/flutter_wasm/example/android/gradle.properties new file mode 100644 index 0000000..94adc3a --- /dev/null +++ b/flutter_wasm/example/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx1536M +android.useAndroidX=true +android.enableJetifier=true diff --git a/flutter_wasm/example/android/gradle/wrapper/gradle-wrapper.properties b/flutter_wasm/example/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..bc6a58a --- /dev/null +++ b/flutter_wasm/example/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip diff --git a/flutter_wasm/example/android/settings.gradle b/flutter_wasm/example/android/settings.gradle new file mode 100644 index 0000000..44e62bc --- /dev/null +++ b/flutter_wasm/example/android/settings.gradle @@ -0,0 +1,11 @@ +include ':app' + +def localPropertiesFile = new File(rootProject.projectDir, "local.properties") +def properties = new Properties() + +assert localPropertiesFile.exists() +localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } + +def flutterSdkPath = properties.getProperty("flutter.sdk") +assert flutterSdkPath != null, "flutter.sdk not set in local.properties" +apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" diff --git a/flutter_wasm/example/lib/main.dart b/flutter_wasm/example/lib/main.dart new file mode 100644 index 0000000..d7f2237 --- /dev/null +++ b/flutter_wasm/example/lib/main.dart @@ -0,0 +1,50 @@ +import 'dart:typed_data'; + +import 'package:flutter/material.dart'; +import 'package:flutter_wasm/flutter_wasm.dart'; + +// int64_t square(int64_t n) { return n * n; } +final _data = Uint8List.fromList([ + 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x06, 0x01, 0x60, // + 0x01, 0x7e, 0x01, 0x7e, 0x03, 0x02, 0x01, 0x00, 0x04, 0x05, 0x01, 0x70, + 0x01, 0x01, 0x01, 0x05, 0x03, 0x01, 0x00, 0x02, 0x06, 0x08, 0x01, 0x7f, + 0x01, 0x41, 0x80, 0x88, 0x04, 0x0b, 0x07, 0x13, 0x02, 0x06, 0x6d, 0x65, + 0x6d, 0x6f, 0x72, 0x79, 0x02, 0x00, 0x06, 0x73, 0x71, 0x75, 0x61, 0x72, + 0x65, 0x00, 0x00, 0x0a, 0x09, 0x01, 0x07, 0x00, 0x20, 0x00, 0x20, 0x00, + 0x7e, 0x0b, +]); + +final _inst = WasmModule(_data).builder().build(); +final _wasmSquare = _inst.lookupFunction('square'); + +void main() { + runApp(const MyApp()); +} + +class MyApp extends StatefulWidget { + const MyApp({Key? key}) : super(key: key); + + @override + State createState() => _MyAppState(); +} + +class _MyAppState extends State { + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + return MaterialApp( + home: Scaffold( + appBar: AppBar( + title: const Text('Wasm example app'), + ), + body: Center( + child: Text('12^2 == ${_wasmSquare(12)}'), + ), + ), + ); + } +} diff --git a/flutter_wasm/example/pubspec.lock b/flutter_wasm/example/pubspec.lock new file mode 100644 index 0000000..c366628 --- /dev/null +++ b/flutter_wasm/example/pubspec.lock @@ -0,0 +1,203 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + args: + dependency: transitive + description: + name: args + url: "https://pub.dartlang.org" + source: hosted + version: "2.3.0" + async: + dependency: transitive + description: + name: async + url: "https://pub.dartlang.org" + source: hosted + version: "2.8.2" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + characters: + dependency: transitive + description: + name: characters + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + charcode: + dependency: transitive + description: + name: charcode + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.1" + clock: + dependency: transitive + description: + name: clock + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + collection: + dependency: transitive + description: + name: collection + url: "https://pub.dartlang.org" + source: hosted + version: "1.15.0" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.3" + fake_async: + dependency: transitive + description: + name: fake_async + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" + ffi: + dependency: transitive + description: + name: ffi + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.2" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.4" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + flutter_wasm: + dependency: "direct main" + description: + path: ".." + relative: true + source: path + version: "0.0.1" + lints: + dependency: transitive + description: + name: lints + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" + matcher: + dependency: transitive + description: + name: matcher + url: "https://pub.dartlang.org" + source: hosted + version: "0.12.11" + meta: + dependency: transitive + description: + name: meta + url: "https://pub.dartlang.org" + source: hosted + version: "1.7.0" + package_config: + dependency: transitive + description: + name: package_config + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.2" + path: + dependency: transitive + description: + name: path + url: "https://pub.dartlang.org" + source: hosted + version: "1.8.0" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_span: + dependency: transitive + description: + name: source_span + url: "https://pub.dartlang.org" + source: hosted + version: "1.8.1" + stack_trace: + dependency: transitive + description: + name: stack_trace + url: "https://pub.dartlang.org" + source: hosted + version: "1.10.0" + stream_channel: + dependency: transitive + description: + name: stream_channel + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + string_scanner: + dependency: transitive + description: + name: string_scanner + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" + test_api: + dependency: transitive + description: + name: test_api + url: "https://pub.dartlang.org" + source: hosted + version: "0.4.3" + typed_data: + dependency: transitive + description: + name: typed_data + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.0" + vector_math: + dependency: transitive + description: + name: vector_math + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + wasm: + dependency: "direct main" + description: + path: "../../wasm" + relative: true + source: path + version: "0.2.0-dev" +sdks: + dart: ">=2.14.0 <3.0.0" + flutter: ">=2.5.0" diff --git a/flutter_wasm/example/pubspec.yaml b/flutter_wasm/example/pubspec.yaml new file mode 100644 index 0000000..37f3462 --- /dev/null +++ b/flutter_wasm/example/pubspec.yaml @@ -0,0 +1,25 @@ +name: flutter_wasm_example +description: Demonstrates how to use the flutter_wasm plugin. +publish_to: 'none' + +environment: + sdk: '>=2.14.0 <3.0.0' + flutter: ">=2.5.0" + +dependencies: + cupertino_icons: ^1.0.2 + flutter: + sdk: flutter + flutter_wasm: + path: ../ + wasm: + path: ../../wasm + +dev_dependencies: + flutter_lints: ^1.0.0 + flutter_test: + sdk: flutter + +flutter: + uses-material-design: true + diff --git a/flutter_wasm/example/test/widget_test.dart b/flutter_wasm/example/test/widget_test.dart new file mode 100644 index 0000000..8e7c033 --- /dev/null +++ b/flutter_wasm/example/test/widget_test.dart @@ -0,0 +1,24 @@ +// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'package:flutter_wasm_example/main.dart'; + +void main() { + testWidgets('Verify wasm runs', (WidgetTester tester) async { + // Build our app and trigger a frame. + await tester.pumpWidget(const MyApp()); + + // Verify that the wasm code runs. + expect( + find.byWidgetPredicate( + (Widget widget) => + widget is Text && widget.data!.startsWith('12^2 == 144'), + ), + findsOneWidget, + ); + }); +} diff --git a/flutter_wasm/lib/flutter_wasm.dart b/flutter_wasm/lib/flutter_wasm.dart new file mode 100644 index 0000000..c48ee40 --- /dev/null +++ b/flutter_wasm/lib/flutter_wasm.dart @@ -0,0 +1,5 @@ +// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +export 'package:wasm/wasm.dart'; diff --git a/flutter_wasm/pubspec.yaml b/flutter_wasm/pubspec.yaml new file mode 100644 index 0000000..84b4f58 --- /dev/null +++ b/flutter_wasm/pubspec.yaml @@ -0,0 +1,27 @@ +name: flutter_wasm +version: 0.0.1 +description: Flutter support for package:wasm +repository: https://github.com/dart-lang/wasm +publish_to: none + +environment: + sdk: '>=2.14.0 <3.0.0' + flutter: ">=2.5.0" + +dependencies: + flutter: + sdk: flutter + wasm: + path: ../wasm + +dev_dependencies: + flutter_lints: ^1.0.0 + flutter_test: + sdk: flutter + +flutter: + plugin: + platforms: + android: + package: dev.dart.flutter_wasm + pluginClass: FlutterWasmPlugin diff --git a/flutter_wasm/test/flutter_wasm_test.dart b/flutter_wasm/test/flutter_wasm_test.dart new file mode 100644 index 0000000..13c2df9 --- /dev/null +++ b/flutter_wasm/test/flutter_wasm_test.dart @@ -0,0 +1,33 @@ +// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +// Test that we can load a wasm module, find a function, and call it. Most of +// the wasm tests are found in package:wasm. This plugin just exports that code. +import 'dart:typed_data'; + +import 'package:flutter_test/flutter_test.dart'; +import 'package:flutter_wasm/flutter_wasm.dart'; + +void main() { + test('basics', () { + // int64_t square(int64_t n) { return n * n; } + var data = Uint8List.fromList([ + 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x06, 0x01, 0x60, // + 0x01, 0x7e, 0x01, 0x7e, 0x03, 0x02, 0x01, 0x00, 0x04, 0x05, 0x01, 0x70, + 0x01, 0x01, 0x01, 0x05, 0x03, 0x01, 0x00, 0x02, 0x06, 0x08, 0x01, 0x7f, + 0x01, 0x41, 0x80, 0x88, 0x04, 0x0b, 0x07, 0x13, 0x02, 0x06, 0x6d, 0x65, + 0x6d, 0x6f, 0x72, 0x79, 0x02, 0x00, 0x06, 0x73, 0x71, 0x75, 0x61, 0x72, + 0x65, 0x00, 0x00, 0x0a, 0x09, 0x01, 0x07, 0x00, 0x20, 0x00, 0x20, 0x00, + 0x7e, 0x0b, + ]); + + var inst = WasmModule(data).builder().build(); + var fn = inst.lookupFunction('square'); + var n = fn(1234) as int; + + expect(n, 1234 * 1234); + + expect(inst.lookupFunction('not_a_function'), isNull); + }); +}