diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 0000000..a5744c1 --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1,4 @@ +include: package:flutter_lints/flutter.yaml + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..161bdcd --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,9 @@ +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures +.cxx diff --git a/android/build.gradle b/android/build.gradle new file mode 100644 index 0000000..47bca7f --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,75 @@ +group 'soko.ekibun.flutter_qjs' +version '1.0-SNAPSHOT' + +buildscript { + ext.kotlin_version = '1.7.10' + repositories { + google() + mavenCentral() + } + + dependencies { + classpath 'com.android.tools.build:gradle:8.0.1' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + mavenCentral() + } +} + +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' + +android { + if (project.android.hasProperty("namespace")) { + namespace 'soko.ekibun.flutter_qjs' + } + + compileSdk 34 + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = '1.8' + } + + externalNativeBuild { + cmake { + path "src/main/cxx/CMakeLists.txt" + version "3.10.2" + } + } + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + test.java.srcDirs += 'src/test/kotlin' + } + + defaultConfig { + minSdkVersion 19 + } + + dependencies { + testImplementation 'org.jetbrains.kotlin:kotlin-test' + testImplementation 'org.mockito:mockito-core:5.0.0' + } + + testOptions { + unitTests.all { + useJUnitPlatform() + + testLogging { + events "passed", "skipped", "failed", "standardOut", "standardError" + outputs.upToDateWhen {false} + showStandardStreams = true + } + } + } +} diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..4acab51 --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'flutter_qjs' diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml new file mode 100644 index 0000000..6cfef06 --- /dev/null +++ b/android/src/main/AndroidManifest.xml @@ -0,0 +1,3 @@ + + diff --git a/android/src/main/kotlin/soko/ekibun/flutter_qjs/FlutterQjsPlugin.kt b/android/src/main/kotlin/soko/ekibun/flutter_qjs/FlutterQjsPlugin.kt new file mode 100644 index 0000000..e01686c --- /dev/null +++ b/android/src/main/kotlin/soko/ekibun/flutter_qjs/FlutterQjsPlugin.kt @@ -0,0 +1,35 @@ +package soko.ekibun.flutter_qjs + +import androidx.annotation.NonNull + +import io.flutter.embedding.engine.plugins.FlutterPlugin +import io.flutter.plugin.common.MethodCall +import io.flutter.plugin.common.MethodChannel +import io.flutter.plugin.common.MethodChannel.MethodCallHandler +import io.flutter.plugin.common.MethodChannel.Result + +/** FlutterQjsPlugin */ +class FlutterQjsPlugin: FlutterPlugin, MethodCallHandler { + /// The MethodChannel that will the communication between Flutter and native Android + /// + /// This local reference serves to register the plugin with the Flutter Engine and unregister it + /// when the Flutter Engine is detached from the Activity + private lateinit var channel : MethodChannel + + override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { + channel = MethodChannel(flutterPluginBinding.binaryMessenger, "flutter_qjs") + channel.setMethodCallHandler(this) + } + + override fun onMethodCall(call: MethodCall, result: Result) { + if (call.method == "getPlatformVersion") { + result.success("Android ${android.os.Build.VERSION.RELEASE}") + } else { + result.notImplemented() + } + } + + override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) { + channel.setMethodCallHandler(null) + } +} diff --git a/android/src/test/kotlin/soko/ekibun/flutter_qjs/FlutterQjsPluginTest.kt b/android/src/test/kotlin/soko/ekibun/flutter_qjs/FlutterQjsPluginTest.kt new file mode 100644 index 0000000..9f9c88a --- /dev/null +++ b/android/src/test/kotlin/soko/ekibun/flutter_qjs/FlutterQjsPluginTest.kt @@ -0,0 +1,27 @@ +package soko.ekibun.flutter_qjs + +import io.flutter.plugin.common.MethodCall +import io.flutter.plugin.common.MethodChannel +import kotlin.test.Test +import org.mockito.Mockito + +/* + * This demonstrates a simple unit test of the Kotlin portion of this plugin's implementation. + * + * Once you have built the plugin's example app, you can run these tests from the command + * line by running `./gradlew testDebugUnitTest` in the `example/android/` directory, or + * you can run them directly from IDEs that support JUnit such as Android Studio. + */ + +internal class FlutterQjsPluginTest { + @Test + fun onMethodCall_getPlatformVersion_returnsExpectedValue() { + val plugin = FlutterQjsPlugin() + + val call = MethodCall("getPlatformVersion", null) + val mockResult: MethodChannel.Result = Mockito.mock(MethodChannel.Result::class.java) + plugin.onMethodCall(call, mockResult) + + Mockito.verify(mockResult).success("Android " + android.os.Build.VERSION.RELEASE) + } +} diff --git a/example/ios/RunnerTests/RunnerTests.swift b/example/ios/RunnerTests/RunnerTests.swift new file mode 100644 index 0000000..8aaf3b5 --- /dev/null +++ b/example/ios/RunnerTests/RunnerTests.swift @@ -0,0 +1,26 @@ +import Flutter +import UIKit +import XCTest + +@testable import flutter_qjs + +// This demonstrates a simple unit test of the Swift portion of this plugin's implementation. +// +// See https://developer.apple.com/documentation/xctest for more information about using XCTest. + +class RunnerTests: XCTestCase { + + func testGetPlatformVersion() { + let plugin = FlutterQjsPlugin() + + let call = FlutterMethodCall(methodName: "getPlatformVersion", arguments: []) + + let resultExpectation = expectation(description: "result block must be called.") + plugin.handle(call) { result in + XCTAssertEqual(result as! String, "iOS " + UIDevice.current.systemVersion) + resultExpectation.fulfill() + } + waitForExpectations(timeout: 1) + } + +} diff --git a/example/linux/flutter/generated_plugin_registrant.cc b/example/linux/flutter/generated_plugin_registrant.cc index 5042a74..86a66cb 100644 --- a/example/linux/flutter/generated_plugin_registrant.cc +++ b/example/linux/flutter/generated_plugin_registrant.cc @@ -7,13 +7,9 @@ #include "generated_plugin_registrant.h" #include -#include void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) flutter_qjs_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterQjsPlugin"); flutter_qjs_plugin_register_with_registrar(flutter_qjs_registrar); - g_autoptr(FlPluginRegistrar) sqlite3_flutter_libs_registrar = - fl_plugin_registry_get_registrar_for_plugin(registry, "Sqlite3FlutterLibsPlugin"); - sqlite3_flutter_libs_plugin_register_with_registrar(sqlite3_flutter_libs_registrar); } diff --git a/example/linux/flutter/generated_plugins.cmake b/example/linux/flutter/generated_plugins.cmake index 6749e87..5929dac 100644 --- a/example/linux/flutter/generated_plugins.cmake +++ b/example/linux/flutter/generated_plugins.cmake @@ -4,7 +4,6 @@ list(APPEND FLUTTER_PLUGIN_LIST flutter_qjs - sqlite3_flutter_libs ) list(APPEND FLUTTER_FFI_PLUGIN_LIST diff --git a/example/macos/Flutter/GeneratedPluginRegistrant.swift b/example/macos/Flutter/GeneratedPluginRegistrant.swift index 4d462c2..d058a0d 100644 --- a/example/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/example/macos/Flutter/GeneratedPluginRegistrant.swift @@ -6,9 +6,7 @@ import FlutterMacOS import Foundation import flutter_qjs -import sqlite3_flutter_libs func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { FlutterQjsPlugin.register(with: registry.registrar(forPlugin: "FlutterQjsPlugin")) - Sqlite3FlutterLibsPlugin.register(with: registry.registrar(forPlugin: "Sqlite3FlutterLibsPlugin")) } diff --git a/example/macos/RunnerTests/RunnerTests.swift b/example/macos/RunnerTests/RunnerTests.swift new file mode 100644 index 0000000..d5c0920 --- /dev/null +++ b/example/macos/RunnerTests/RunnerTests.swift @@ -0,0 +1,27 @@ +import FlutterMacOS +import Cocoa +import XCTest + +@testable import flutter_qjs + +// This demonstrates a simple unit test of the Swift portion of this plugin's implementation. +// +// See https://developer.apple.com/documentation/xctest for more information about using XCTest. + +class RunnerTests: XCTestCase { + + func testGetPlatformVersion() { + let plugin = FlutterQjsPlugin() + + let call = FlutterMethodCall(methodName: "getPlatformVersion", arguments: []) + + let resultExpectation = expectation(description: "result block must be called.") + plugin.handle(call) { result in + XCTAssertEqual(result as! String, + "macOS " + ProcessInfo.processInfo.operatingSystemVersionString) + resultExpectation.fulfill() + } + waitForExpectations(timeout: 1) + } + +} diff --git a/example/pubspec.lock b/example/pubspec.lock index 8ece711..224f900 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -90,14 +90,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.7.0" - js: - dependency: transitive - description: - name: js - sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 - url: "https://pub.dev" - source: hosted - version: "0.6.7" leak_tracker: dependency: transitive description: @@ -167,22 +159,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.10.0" - sqlite3: - dependency: "direct main" - description: - name: sqlite3 - sha256: "1abbeb84bf2b1a10e5e1138c913123c8aa9d83cd64e5f9a0dd847b3c83063202" - url: "https://pub.dev" - source: hosted - version: "2.4.2" - sqlite3_flutter_libs: - dependency: "direct main" - description: - name: sqlite3_flutter_libs - sha256: d6c31c8511c441d1f12f20b607343df1afe4eddf24a1cf85021677c8eea26060 - url: "https://pub.dev" - source: hosted - version: "0.5.20" stack_trace: dependency: transitive description: @@ -240,5 +216,5 @@ packages: source: hosted version: "13.0.0" sdks: - dart: ">=3.3.0 <4.0.0" + dart: ">=3.3.0-279.1.beta <4.0.0" flutter: ">=3.0.0" diff --git a/example/test/widget_test.dart b/example/test/widget_test.dart new file mode 100644 index 0000000..e36d3c2 --- /dev/null +++ b/example/test/widget_test.dart @@ -0,0 +1,27 @@ +// This is a basic Flutter widget test. +// +// To perform an interaction with a widget in your test, use the WidgetTester +// utility in the flutter_test package. For example, you can send tap and scroll +// gestures. You can also use WidgetTester to find child widgets in the widget +// tree, read text, and verify that the values of widget properties are correct. + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'package:flutter_qjs_example/main.dart'; + +void main() { + testWidgets('Verify Platform version', (WidgetTester tester) async { + // Build our app and trigger a frame. + await tester.pumpWidget(const MyApp()); + + // Verify that platform version is retrieved. + expect( + find.byWidgetPredicate( + (Widget widget) => widget is Text && + widget.data!.startsWith('Running on:'), + ), + findsOneWidget, + ); + }); +} diff --git a/example/windows/flutter/generated_plugin_registrant.cc b/example/windows/flutter/generated_plugin_registrant.cc index ace0f91..1c0e883 100644 --- a/example/windows/flutter/generated_plugin_registrant.cc +++ b/example/windows/flutter/generated_plugin_registrant.cc @@ -7,11 +7,8 @@ #include "generated_plugin_registrant.h" #include -#include void RegisterPlugins(flutter::PluginRegistry* registry) { FlutterQjsPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("FlutterQjsPlugin")); - Sqlite3FlutterLibsPluginRegisterWithRegistrar( - registry->GetRegistrarForPlugin("Sqlite3FlutterLibsPlugin")); } diff --git a/example/windows/flutter/generated_plugins.cmake b/example/windows/flutter/generated_plugins.cmake index bd22af4..876d3d9 100644 --- a/example/windows/flutter/generated_plugins.cmake +++ b/example/windows/flutter/generated_plugins.cmake @@ -4,7 +4,6 @@ list(APPEND FLUTTER_PLUGIN_LIST flutter_qjs - sqlite3_flutter_libs ) list(APPEND FLUTTER_FFI_PLUGIN_LIST diff --git a/ios/Classes/FlutterQjsPlugin.swift b/ios/Classes/FlutterQjsPlugin.swift new file mode 100644 index 0000000..3a307bd --- /dev/null +++ b/ios/Classes/FlutterQjsPlugin.swift @@ -0,0 +1,19 @@ +import Flutter +import UIKit + +public class FlutterQjsPlugin: NSObject, FlutterPlugin { + public static func register(with registrar: FlutterPluginRegistrar) { + let channel = FlutterMethodChannel(name: "flutter_qjs", binaryMessenger: registrar.messenger()) + let instance = FlutterQjsPlugin() + registrar.addMethodCallDelegate(instance, channel: channel) + } + + public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { + switch call.method { + case "getPlatformVersion": + result("iOS " + UIDevice.current.systemVersion) + default: + result(FlutterMethodNotImplemented) + } + } +} diff --git a/linux/flutter_qjs_plugin_private.h b/linux/flutter_qjs_plugin_private.h new file mode 100644 index 0000000..5c450f8 --- /dev/null +++ b/linux/flutter_qjs_plugin_private.h @@ -0,0 +1,10 @@ +#include + +#include "include/flutter_qjs/flutter_qjs_plugin.h" + +// This file exposes some plugin internals for unit testing. See +// https://github.com/flutter/flutter/issues/88724 for current limitations +// in the unit-testable API. + +// Handles the getPlatformVersion method call. +FlMethodResponse *get_platform_version(); diff --git a/linux/test/flutter_qjs_plugin_test.cc b/linux/test/flutter_qjs_plugin_test.cc new file mode 100644 index 0000000..b9e9bbe --- /dev/null +++ b/linux/test/flutter_qjs_plugin_test.cc @@ -0,0 +1,31 @@ +#include +#include +#include + +#include "include/flutter_qjs/flutter_qjs_plugin.h" +#include "flutter_qjs_plugin_private.h" + +// This demonstrates a simple unit test of the C portion of this plugin's +// implementation. +// +// Once you have built the plugin's example app, you can run these tests +// from the command line. For instance, for a plugin called my_plugin +// built for x64 debug, run: +// $ build/linux/x64/debug/plugins/my_plugin/my_plugin_test + +namespace flutter_qjs { +namespace test { + +TEST(FlutterQjsPlugin, GetPlatformVersion) { + g_autoptr(FlMethodResponse) response = get_platform_version(); + ASSERT_NE(response, nullptr); + ASSERT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response)); + FlValue* result = fl_method_success_response_get_result( + FL_METHOD_SUCCESS_RESPONSE(response)); + ASSERT_EQ(fl_value_get_type(result), FL_VALUE_TYPE_STRING); + // The full string varies, so just validate that it has the right format. + EXPECT_THAT(fl_value_get_string(result), testing::StartsWith("Linux ")); +} + +} // namespace test +} // namespace flutter_qjs diff --git a/windows/flutter_qjs_plugin.h b/windows/flutter_qjs_plugin.h new file mode 100644 index 0000000..5c83686 --- /dev/null +++ b/windows/flutter_qjs_plugin.h @@ -0,0 +1,31 @@ +#ifndef FLUTTER_PLUGIN_FLUTTER_QJS_PLUGIN_H_ +#define FLUTTER_PLUGIN_FLUTTER_QJS_PLUGIN_H_ + +#include +#include + +#include + +namespace flutter_qjs { + +class FlutterQjsPlugin : public flutter::Plugin { + public: + static void RegisterWithRegistrar(flutter::PluginRegistrarWindows *registrar); + + FlutterQjsPlugin(); + + virtual ~FlutterQjsPlugin(); + + // Disallow copy and assign. + FlutterQjsPlugin(const FlutterQjsPlugin&) = delete; + FlutterQjsPlugin& operator=(const FlutterQjsPlugin&) = delete; + + // Called when a method is called on this plugin's channel from Dart. + void HandleMethodCall( + const flutter::MethodCall &method_call, + std::unique_ptr> result); +}; + +} // namespace flutter_qjs + +#endif // FLUTTER_PLUGIN_FLUTTER_QJS_PLUGIN_H_ diff --git a/windows/flutter_qjs_plugin_c_api.cpp b/windows/flutter_qjs_plugin_c_api.cpp new file mode 100644 index 0000000..3221853 --- /dev/null +++ b/windows/flutter_qjs_plugin_c_api.cpp @@ -0,0 +1,12 @@ +#include "include/flutter_qjs/flutter_qjs_plugin_c_api.h" + +#include + +#include "flutter_qjs_plugin.h" + +void FlutterQjsPluginCApiRegisterWithRegistrar( + FlutterDesktopPluginRegistrarRef registrar) { + flutter_qjs::FlutterQjsPlugin::RegisterWithRegistrar( + flutter::PluginRegistrarManager::GetInstance() + ->GetRegistrar(registrar)); +} diff --git a/windows/include/flutter_qjs/flutter_qjs_plugin_c_api.h b/windows/include/flutter_qjs/flutter_qjs_plugin_c_api.h new file mode 100644 index 0000000..02cc087 --- /dev/null +++ b/windows/include/flutter_qjs/flutter_qjs_plugin_c_api.h @@ -0,0 +1,23 @@ +#ifndef FLUTTER_PLUGIN_FLUTTER_QJS_PLUGIN_C_API_H_ +#define FLUTTER_PLUGIN_FLUTTER_QJS_PLUGIN_C_API_H_ + +#include + +#ifdef FLUTTER_PLUGIN_IMPL +#define FLUTTER_PLUGIN_EXPORT __declspec(dllexport) +#else +#define FLUTTER_PLUGIN_EXPORT __declspec(dllimport) +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +FLUTTER_PLUGIN_EXPORT void FlutterQjsPluginCApiRegisterWithRegistrar( + FlutterDesktopPluginRegistrarRef registrar); + +#if defined(__cplusplus) +} // extern "C" +#endif + +#endif // FLUTTER_PLUGIN_FLUTTER_QJS_PLUGIN_C_API_H_ diff --git a/windows/test/flutter_qjs_plugin_test.cpp b/windows/test/flutter_qjs_plugin_test.cpp new file mode 100644 index 0000000..486b0da --- /dev/null +++ b/windows/test/flutter_qjs_plugin_test.cpp @@ -0,0 +1,43 @@ +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "flutter_qjs_plugin.h" + +namespace flutter_qjs { +namespace test { + +namespace { + +using flutter::EncodableMap; +using flutter::EncodableValue; +using flutter::MethodCall; +using flutter::MethodResultFunctions; + +} // namespace + +TEST(FlutterQjsPlugin, GetPlatformVersion) { + FlutterQjsPlugin plugin; + // Save the reply value from the success callback. + std::string result_string; + plugin.HandleMethodCall( + MethodCall("getPlatformVersion", std::make_unique()), + std::make_unique>( + [&result_string](const EncodableValue* result) { + result_string = std::get(*result); + }, + nullptr, nullptr)); + + // Since the exact string varies by host, just ensure that it's a string + // with the expected format. + EXPECT_TRUE(result_string.rfind("Windows ", 0) == 0); +} + +} // namespace test +} // namespace flutter_qjs