commit 7d68ed0f6cd7b99f88e826de11634412cb6baf67 Author: yangjie <168149434@qq.com> Date: Sun Nov 17 16:01:34 2024 +0800 1 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..29a3a50 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# 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 +.pub-cache/ +.pub/ +/build/ + +# 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/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..38561a6 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,187 @@ +## 0.8.11 +- feat: 增加PlatformService::getAssetPath方法 +- enhance: CGSize增加创建方法 +- enhance: 新增FluttifyBroadcastEventChannel, 一律返回Intent +- enhance: Intent增加获取bundle + +## 0.8.10 +- feat: 增加UIImageView的创建 +- enhance: UIView增加setAnchorPoint +- enhance: CGRect增加属性获取方法 + +## 0.8.9 +- fix: objc application的回调不再传输NSDictionary类型的参数, 防止崩溃 + +## 0.8.8 +- enhance: CGSize增加width和height + +## 0.8.7 +- enhance: 增加ImageProviderX + +## 0.8.6 +- enhance: 增加java_lang_Throwable + +## 0.8.5 +- enhance: 接口类增加sbInstance方法 + +## 0.8.4 +- enhance: 增加android_view_SurfaceHolder_Callback + +## 0.8.3 +- enhance: 增加android_view_SurfaceView + +## 0.8.2 +- feat: android_location_Location增加setter + +## 0.8.1 +- feat: 增加startActivityForResult方法 +- feat: 增加uri2ImageData +- feat: UIViewController::get +- feat: android_location_Location增加创建方法 + +## 0.8.0 +- fix: UIImage scale问题处理 + +## 0.7.3 +- feat: 增加java.io.File + +## 0.7.2 +- feat: 增加java_io_Closeable + +## 0.7.1 +- feat: Bundle增加getString和putString +- enhance: ios使用static_framework +- enhance: 适配1.17 + +## 0.7.0 +- enhance: [breaking change] 去除CoreLocation相关逻辑, 计划分离到core_location_fluttiy插件中去 +- feat: 增加android_view_View_OnTouchListener类; 增加ui_view.widget +- feat: 增加av_audio_session_category_options +- feat: CGRect增加create方法 +- feat: android.graphics.Bitmap和UIImage各自增加从原生素材创建Image的方法 + +## 0.6.1 +- enhance: android: *Handler的args参数使用Any类型, 内部再做转换 +- feat: 增加批处理方法 + +## 0.6.0 +- enhance: [breaking change] Ref类内的方法和属性都加上__后缀, 防止和子类冲突 + +## 0.5.1 +- feat: NSError增加获取code和description的方法 + +## 0.5.0 +- enhance: [breaking change] tag -> tag__ + +## 0.4.18 +- feat: 增加UIViewController + +## 0.4.17 +- feat: 使用System.identityHashCode代替hashCode方法 +- feat: 增加android.view.View.OnClickListener类 +- feat: 增加startActivity/presentViewController方法 + +## 0.4.16 +- feat: 增加NSValue类 + +## 0.4.15 +- enhance: 简化platform方法 +- enhance: 补上漏掉的log开关 +- enhance: 迁移创建方法到对应类的handler里去 +- feat: 增加android.app.Notification类 + +## 0.4.14 +- enhance: CLLocationCoordinate2D增加批量创建方法 + +## 0.4.13 +- enhance: 优化批量释放日志 +- feat: UIView增加hidden和setHidden + +## 0.4.12 +- enhance: 优化platform方法里的释放逻辑 + +## 0.4.11 +- enhance: Ref增加批处理释放对象方法 + +## 0.4.10 +- feat: 增加org_json_JSONObject类 + +## 0.4.9 +- feat: 增加android_view_View_OnApplyWindowInsetsListener类 + +## 0.4.8 +- feat: Bitmap增加批量创建方法 + +## 0.4.7 +- refactor: PlatformFactory统一为PlatformService +- feat: 增加ns_operation类 + +## 0.4.6 +- feat: 增加一些通用的typedef + +## 0.4.5+1 +- fix: onAttachedToEngine中的Plugin对象应该使用this + +## 0.4.5 +- fix: PlatformFactory的activity是可选类型; +- enhance: android_util_Pair获取first和second都返回Object + +## 0.4.4 +- enhance: 适配新版embedding +- refactor: method channel放到objects文件里 + +## 0.4.3 +- feat: 增加为对象动态添加属性的方法(目前仅限ios端, android理论上可以再加全局Map实现,但是目前没有碰到此类需求) + +## 0.4.2 +- feat: 增加java_io_Serializable + +## 0.4.1 +- feat: 增加android_os_Binder + +## 0.4.0 +- refactor: 可以放进类的静态方法替换全局函数 + +## 0.3.0 +- refactor: 函数代替类 +- chore: 提升gradle相关版本 + +## 0.2.7 +- feat: 增加pending_intent类 + +## 0.2.6 +- feat: android端增加BroadcastReceiver统一接收广播 + +## 0.2.5 +- feat: CLHeading实现magneticHeading,trueHeading,headingAccuracy + +## 0.2.4 +- feat: android_location_Location增加bearing, altitude, accuracy, speed + +## 0.2.3 +- feat: 增加android_content_ContentProvider + +## 0.2.2 +- feat: 实现UIEdgeInsets的属性 + +## 0.2.1 +- fix: [objc] 每个.h文件都import + +## 0.2.0 +- [breaking change] 整理工厂方法 + +## 0.1.5 +- feat: 增加cgpoint的创建支持,获取x和y + +## 0.1.4 +- feat: 增加android_graphics_Point的创建, getX, getY的支持 + +## 0.1.3 +feat: 增加NSData + +## 0.1.2 +- 新增android.app.Activity#getIntent() +- feat: android端的Intent处理容器 + +## 0.1.1 +- 增加android.content.Intent diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..8335662 --- /dev/null +++ b/LICENSE @@ -0,0 +1,13 @@ +Copyright 2020 yohom + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..f03bdb5 --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +# `Fluttify`基础设施 + +所有基于`Fluttify`的插件公共的部分, 当然不基于`Fluttify`的插件理论上也可以使用. + +主要实现一些基础设施和系统类的实现. \ No newline at end of file diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 0000000..280c88e --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1,7 @@ +include: package:pedantic/analysis_options.yaml + +linter: + rules: + camel_case_types: false + camel_case_extensions: false + omit_local_variable_types: false \ No newline at end of file diff --git a/android/build.gradle b/android/build.gradle new file mode 100644 index 0000000..bba2693 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,70 @@ +group 'me.yohom.foundation_fluttify' +version '1.0-SNAPSHOT' + +buildscript { + ext.kotlin_version = "1.8.22" + repositories { + google() + mavenCentral() + } + + dependencies { + classpath("com.android.tools.build:gradle:8.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 { + if (project.android.hasProperty("namespace")) { + namespace = "me.yohom.foundation_fluttify" + } + + compileSdk = 34 + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = JavaVersion.VERSION_1_8 + } + + sourceSets { + main.java.srcDirs += "src/main/kotlin" + test.java.srcDirs += "src/test/kotlin" + } + + defaultConfig { + minSdk = 21 + } + + 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/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +android.useAndroidX=true +android.enableJetifier=true diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..81365b5 --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'foundation_fluttify' diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml new file mode 100644 index 0000000..e248719 --- /dev/null +++ b/android/src/main/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + + + diff --git a/android/src/main/java/me/yohom/foundation_fluttify/core/FluttifyMessageCodec.java b/android/src/main/java/me/yohom/foundation_fluttify/core/FluttifyMessageCodec.java new file mode 100644 index 0000000..d9666fb --- /dev/null +++ b/android/src/main/java/me/yohom/foundation_fluttify/core/FluttifyMessageCodec.java @@ -0,0 +1,82 @@ +package me.yohom.foundation_fluttify.core; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import io.flutter.plugin.common.StandardMessageCodec; +import me.yohom.foundation_fluttify.FoundationFluttifyPluginKt; + +import java.io.ByteArrayOutputStream; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.util.*; + +public class FluttifyMessageCodec extends StandardMessageCodec { + private static final Charset UTF8 = Charset.forName("UTF8"); + + // 总体逻辑, 先尝试使用标准编解码进行处理, 如果发生异常再使用自定义的编解码处理, 再不行就只能抛异常了 + private static final byte ARRAY = 125; + private static final byte ENUM = 126; + private static final byte REF = 127; + + @Override + protected void writeValue(@NonNull ByteArrayOutputStream stream, @NonNull Object value) { + try { + super.writeValue(stream, value); + } catch (IllegalArgumentException e) { + // 对象数组转换 + if (value instanceof Object[]) { + stream.write(ARRAY); + Object[] array = (Object[]) value; + writeSize(stream, array.length); + for (Object item : array) { + writeValue(stream, item); + } + } + // 枚举值传索引 + else if (value instanceof Enum) { + stream.write(ENUM); + writeInt(stream, ((Enum) value).ordinal()); + } else { + final String refId = value.getClass().getName() + ":" + System.identityHashCode(value); + // 放入HEAP + FoundationFluttifyPluginKt.getHEAP().put(refId, value); + + stream.write(REF); + writeBytes(stream, refId.getBytes(UTF8)); + } + } + } + + @Nullable + protected Object readValueOfType(byte type, @NonNull ByteBuffer buffer) { + Object result; + try { + result = super.readValueOfType(type, buffer); + } catch (IllegalArgumentException e) { + switch (type) { + case ARRAY: + final int size = readSize(buffer); + final List list = new ArrayList<>(size); + int i = 0; + while (i < size) { + list.add(readValue(buffer)); + i++; + } + result = list.toArray(); + break; + case ENUM: + result = buffer.getInt(); + break; + case REF: + final byte[] bytes = readBytes(buffer); + result = FoundationFluttifyPluginKt.getHEAP().get(new String(bytes, UTF8)); + break; + default: + result = null; + } + } + + return result; + + } +} \ No newline at end of file diff --git a/android/src/main/kotlin/me/yohom/foundation_fluttify/FoundationFluttifyPlugin.kt b/android/src/main/kotlin/me/yohom/foundation_fluttify/FoundationFluttifyPlugin.kt new file mode 100644 index 0000000..ced14d7 --- /dev/null +++ b/android/src/main/kotlin/me/yohom/foundation_fluttify/FoundationFluttifyPlugin.kt @@ -0,0 +1,157 @@ +package me.yohom.foundation_fluttify + +import android.app.Activity +import android.content.Context +import io.flutter.embedding.engine.plugins.FlutterPlugin +import io.flutter.embedding.engine.plugins.activity.ActivityAware +import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding +import io.flutter.plugin.common.BinaryMessenger +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 +import io.flutter.plugin.common.PluginRegistry.Registrar +import io.flutter.plugin.common.StandardMethodCodec +import io.flutter.plugin.platform.PlatformViewRegistry +import me.yohom.foundation_fluttify.android.app.ActivityHandler +import me.yohom.foundation_fluttify.android.app.ApplicationHandler +import me.yohom.foundation_fluttify.android.app.NotificationHandler +import me.yohom.foundation_fluttify.android.app.PendingIntentHandler +import me.yohom.foundation_fluttify.android.content.BroadcastReceiverHandler +import me.yohom.foundation_fluttify.android.content.ContextHandler +import me.yohom.foundation_fluttify.android.content.IntentFilterHandler +import me.yohom.foundation_fluttify.android.content.IntentHandler +import me.yohom.foundation_fluttify.android.graphics.BitmapHandler +import me.yohom.foundation_fluttify.android.graphics.PointHandler +import me.yohom.foundation_fluttify.android.location.LocationHandler +import me.yohom.foundation_fluttify.android.os.BundleHandler +import me.yohom.foundation_fluttify.android.util.PairHandler +import me.yohom.foundation_fluttify.android.view.SurfaceHolderHandler +import me.yohom.foundation_fluttify.android.view.SurfaceViewHandler +import me.yohom.foundation_fluttify.android.view.ViewGroupHandler +import me.yohom.foundation_fluttify.android.view.ViewHandler +import me.yohom.foundation_fluttify.android.widget.ImageViewHandler +import me.yohom.foundation_fluttify.core.FluttifyMessageCodec +import me.yohom.foundation_fluttify.core.PlatformService +import me.yohom.foundation_fluttify.java.io.FileHandler +import me.yohom.foundation_fluttify.platform_view.android_opengl_GLSurfaceViewFactory +import me.yohom.foundation_fluttify.platform_view.android_view_SurfaceViewFactory +import me.yohom.foundation_fluttify.platform_view.android_widget_FrameLayoutFactory + + +// The stack that exists on the Dart side for a method call is enabled only when the MethodChannel passing parameters are limited +val STACK = mutableMapOf() + +// Container for Dart side random access objects +val HEAP = mutableMapOf() + +// whether enable log or not +var enableLog: Boolean = true + +// method channel for foundation +lateinit var gMethodChannel: MethodChannel + +class FoundationFluttifyPlugin : FlutterPlugin, ActivityAware, MethodCallHandler { + private var applicationContext: Context? = null + private var activity: Activity? = null + private var activityBinding: ActivityPluginBinding? = null + private var pluginBinding: FlutterPlugin.FlutterPluginBinding? = null + private var registrar: Registrar? = null + private var platformViewRegistry: PlatformViewRegistry? = null + private var binaryMessenger: BinaryMessenger? = null + + companion object { + @JvmStatic + fun registerWith(registrar: Registrar) { + val plugin = FoundationFluttifyPlugin() + plugin.registrar = registrar + plugin.platformViewRegistry = registrar.platformViewRegistry() + plugin.binaryMessenger = registrar.messenger() + plugin.activity = registrar.activity() + plugin.applicationContext = registrar.activity()?.applicationContext + plugin.platformViewRegistry?.registerViewFactory("me.yohom/foundation_fluttify/android.view.SurfaceView", android_view_SurfaceViewFactory(registrar.messenger())) + plugin.platformViewRegistry?.registerViewFactory("me.yohom/foundation_fluttify/android.widget.FrameLayout", android_widget_FrameLayoutFactory()) + plugin.platformViewRegistry?.registerViewFactory("me.yohom/foundation_fluttify/android.opengl.GLSurfaceView", android_opengl_GLSurfaceViewFactory()) + + gMethodChannel = MethodChannel( + registrar.messenger(), + "com.fluttify/foundation_method", + StandardMethodCodec(FluttifyMessageCodec()) + ) + gMethodChannel.setMethodCallHandler(plugin) + + } + } + + override fun onMethodCall(methodCall: MethodCall, methodResult: Result) { + val rawArgs = methodCall.arguments ?: mapOf() + methodCall.method.run { + when { + startsWith("android.app.Application::") -> ApplicationHandler(methodCall.method, rawArgs, methodResult, applicationContext) + startsWith("android.app.Activity::") -> ActivityHandler(methodCall.method, rawArgs, methodResult, activity) + startsWith("android.app.PendingIntent::") -> PendingIntentHandler(methodCall.method, rawArgs, methodResult) + startsWith("android.app.Notification::") -> NotificationHandler(methodCall.method, rawArgs, methodResult, activity) + startsWith("android.os.Bundle::") -> BundleHandler(methodCall.method, rawArgs, methodResult) + startsWith("android.content.Intent::") -> IntentHandler(methodCall.method, rawArgs, methodResult) + startsWith("android.content.Context::") -> ContextHandler(methodCall.method, rawArgs, methodResult) + startsWith("android.content.BroadcastReceiver::") -> BroadcastReceiverHandler(methodCall.method, rawArgs, registrar?.messenger(), methodResult) + startsWith("android.content.IntentFilter::") -> IntentFilterHandler(methodCall.method, rawArgs, methodResult) + startsWith("android.graphics.Bitmap::") -> BitmapHandler(methodCall.method, rawArgs, methodResult, activity) + startsWith("android.graphics.Point::") -> PointHandler(methodCall.method, rawArgs, methodResult) + startsWith("android.location.Location::") -> LocationHandler(methodCall.method, rawArgs, methodResult) + startsWith("android.util.Pair::") -> PairHandler(methodCall.method, rawArgs, methodResult) + startsWith("android.view.View::") -> ViewHandler(methodCall.method, rawArgs, methodResult) + startsWith("android.view.SurfaceView::") -> SurfaceViewHandler(methodCall.method, rawArgs, methodResult) + startsWith("android.view.SurfaceHolder::") -> SurfaceHolderHandler(binaryMessenger, methodCall.method, rawArgs, methodResult) + startsWith("android.view.ViewGroup::") -> ViewGroupHandler(methodCall.method, rawArgs, methodResult) + startsWith("android.widget.ImageView::") -> ImageViewHandler(methodCall.method, rawArgs, methodResult, activity) + startsWith("java.io.File::") -> FileHandler(methodCall.method, rawArgs, methodResult) + startsWith("PlatformService::") -> PlatformService(methodCall.method, rawArgs as Map, methodResult, activityBinding, pluginBinding, registrar) + else -> methodResult.notImplemented() + } + } + } + + override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) { + applicationContext = binding.applicationContext + pluginBinding = binding + platformViewRegistry = binding.platformViewRegistry + binaryMessenger = binding.binaryMessenger + + gMethodChannel = MethodChannel( + binding.binaryMessenger, + "com.fluttify/foundation_method", + StandardMethodCodec(FluttifyMessageCodec()) + ) + gMethodChannel.setMethodCallHandler(this) + } + + override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) { + pluginBinding = null + activity = null + activityBinding = null + } + + override fun onAttachedToActivity(binding: ActivityPluginBinding) { + activity = binding.activity + activityBinding = binding + platformViewRegistry?.registerViewFactory("me.yohom/foundation_fluttify/android.view.SurfaceView", android_view_SurfaceViewFactory(binaryMessenger)) + platformViewRegistry?.registerViewFactory("me.yohom/foundation_fluttify/android.widget.FrameLayout", android_widget_FrameLayoutFactory()) + platformViewRegistry?.registerViewFactory("me.yohom/foundation_fluttify/android.opengl.GLSurfaceView", android_opengl_GLSurfaceViewFactory()) + } + + override fun onDetachedFromActivity() { + activity = null + activityBinding = null + } + + override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) { + activity = binding.activity + activityBinding = binding + } + + override fun onDetachedFromActivityForConfigChanges() { + activity = null + activityBinding = null + } +} \ No newline at end of file diff --git a/android/src/main/kotlin/me/yohom/foundation_fluttify/android/app/ActivityHandler.kt b/android/src/main/kotlin/me/yohom/foundation_fluttify/android/app/ActivityHandler.kt new file mode 100644 index 0000000..a0e91c7 --- /dev/null +++ b/android/src/main/kotlin/me/yohom/foundation_fluttify/android/app/ActivityHandler.kt @@ -0,0 +1,17 @@ +package me.yohom.foundation_fluttify.android.app + +import android.app.Activity +import io.flutter.plugin.common.MethodChannel +import me.yohom.foundation_fluttify.core.__this__ + +fun ActivityHandler(method: String, args: Any, methodResult: MethodChannel.Result, context: Activity?) { + when (method) { + "android.app.Activity::getIntent" -> { + methodResult.success(args.__this__().intent) + } + "android.app.Activity::get" -> { + methodResult.success(context) + } + else -> methodResult.notImplemented() + } +} \ No newline at end of file diff --git a/android/src/main/kotlin/me/yohom/foundation_fluttify/android/app/ApplicationHandler.kt b/android/src/main/kotlin/me/yohom/foundation_fluttify/android/app/ApplicationHandler.kt new file mode 100644 index 0000000..dc7ed29 --- /dev/null +++ b/android/src/main/kotlin/me/yohom/foundation_fluttify/android/app/ApplicationHandler.kt @@ -0,0 +1,13 @@ +package me.yohom.foundation_fluttify.android.app + +import android.content.Context +import io.flutter.plugin.common.MethodChannel + +fun ApplicationHandler(method: String, args: Any, methodResult: MethodChannel.Result, context: Context?) { + when (method) { + "android.app.Application::get" -> { + methodResult.success(context) + } + else -> methodResult.notImplemented() + } +} \ No newline at end of file diff --git a/android/src/main/kotlin/me/yohom/foundation_fluttify/android/app/NotificationHandler.kt b/android/src/main/kotlin/me/yohom/foundation_fluttify/android/app/NotificationHandler.kt new file mode 100644 index 0000000..4cb89f3 --- /dev/null +++ b/android/src/main/kotlin/me/yohom/foundation_fluttify/android/app/NotificationHandler.kt @@ -0,0 +1,65 @@ +package me.yohom.foundation_fluttify.android.app + +import android.app.Activity +import android.app.Notification +import android.app.NotificationChannel +import android.app.NotificationManager +import android.content.Context +import android.graphics.Color +import android.os.Build +import io.flutter.plugin.common.MethodChannel +import me.yohom.foundation_fluttify.HEAP +import me.yohom.foundation_fluttify.enableLog + +fun NotificationHandler(method: String, rawArgs: Any, methodResult: MethodChannel.Result, activity: Activity?) { + when (method) { + "android.app.Notification::create" -> { + val args = rawArgs as Map + if (activity == null) { + methodResult.error("activity cannot be null", "activity cannot be null", "activity cannot be null") + } else { + val contentTitle = args["contentTitle"] as String + val contentText = args["contentText"] as String + val `when` = args["when"] as Long + val channelId = args["channelId"] as String + val channelName = args["channelName"] as String + val enableLights = args["enableLights"] as Boolean + val showBadge = args["showBadge"] as Boolean + + if (enableLog) { + android.util.Log.d("Notification create: ", "contentTitle: $contentTitle, contentText: $contentText, when: $`when`, channelId: $channelId, channelName: $channelName, enableLights: $enableLights, showBadge: $showBadge") + } + + val notificationManager: NotificationManager = activity.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + + // Android O上对Notification进行了修改,如果设置的targetSDKVersion>=26建议使用此种方式创建通知栏 + val builder: Notification.Builder = if (Build.VERSION.SDK_INT >= 26) { + val notificationChannel = NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_DEFAULT) + .apply { + enableLights(enableLights) //是否在桌面icon右上角展示小圆点 + lightColor = Color.BLUE //小圆点颜色 + setShowBadge(showBadge) //是否在久按桌面图标时显示此渠道的通知 + } + + notificationManager.createNotificationChannel(notificationChannel) + + Notification.Builder(activity.applicationContext, channelId) + } else { + Notification.Builder(activity.applicationContext) + } + + // TODO: 从flutter传icon数据过来? + val iconId = activity.resources.getIdentifier("ic_launcher", "mipmap", activity.packageName) + + builder.setSmallIcon(iconId) + .setContentTitle(contentTitle) + .setContentText(contentText) + .setWhen(`when`) + val notification = builder.build() + + methodResult.success(notification) + } + } + else -> methodResult.notImplemented() + } +} \ No newline at end of file diff --git a/android/src/main/kotlin/me/yohom/foundation_fluttify/android/app/PendingIntentHandler.kt b/android/src/main/kotlin/me/yohom/foundation_fluttify/android/app/PendingIntentHandler.kt new file mode 100644 index 0000000..75289bd --- /dev/null +++ b/android/src/main/kotlin/me/yohom/foundation_fluttify/android/app/PendingIntentHandler.kt @@ -0,0 +1,9 @@ +package me.yohom.foundation_fluttify.android.app + +import io.flutter.plugin.common.MethodChannel + +fun PendingIntentHandler(method: String, args: Any, methodResult: MethodChannel.Result) { + when (method) { + else -> methodResult.notImplemented() + } +} \ No newline at end of file diff --git a/android/src/main/kotlin/me/yohom/foundation_fluttify/android/content/BroadcastReceiverHandler.kt b/android/src/main/kotlin/me/yohom/foundation_fluttify/android/content/BroadcastReceiverHandler.kt new file mode 100644 index 0000000..01acefa --- /dev/null +++ b/android/src/main/kotlin/me/yohom/foundation_fluttify/android/content/BroadcastReceiverHandler.kt @@ -0,0 +1,29 @@ +package me.yohom.foundation_fluttify.android.content + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import io.flutter.plugin.common.BinaryMessenger +import io.flutter.plugin.common.MethodChannel +import me.yohom.foundation_fluttify.HEAP + +fun BroadcastReceiverHandler(method: String, rawArgs: Any, binaryMessenger: BinaryMessenger?, methodResult: MethodChannel.Result) { + when (method) { + "android.content.BroadcastReceiver::create" -> { + val receiver = object : BroadcastReceiver() { + override fun onReceive(context: Context?, intent: Intent?) { + if (binaryMessenger != null) { + MethodChannel(binaryMessenger, "android.content.BroadcastReceiver::create::Callback") + .invokeMethod( + "Callback::android.content.BroadcastReceiver::onReceive", + mapOf("intent" to intent) + ) + } + } + } + + methodResult.success(receiver) + } + else -> methodResult.notImplemented() + } +} \ No newline at end of file diff --git a/android/src/main/kotlin/me/yohom/foundation_fluttify/android/content/ContextHandler.kt b/android/src/main/kotlin/me/yohom/foundation_fluttify/android/content/ContextHandler.kt new file mode 100644 index 0000000..c61742b --- /dev/null +++ b/android/src/main/kotlin/me/yohom/foundation_fluttify/android/content/ContextHandler.kt @@ -0,0 +1,24 @@ +package me.yohom.foundation_fluttify.android.content + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.IntentFilter +import io.flutter.plugin.common.MethodChannel +import me.yohom.foundation_fluttify.core.__this__ +import me.yohom.foundation_fluttify.core.get + +fun ContextHandler(method: String, rawArgs: Any, methodResult: MethodChannel.Result) { + when (method) { + "android.content.Context::registerReceiver" -> { + val broadcastReceiver = rawArgs["broadcastReceiver"] as BroadcastReceiver + val intentFilter = rawArgs["intentFilter"] as IntentFilter + + val context: Context = rawArgs.__this__() + + val intent = context.registerReceiver(broadcastReceiver, intentFilter) + + methodResult.success(intent) + } + else -> methodResult.notImplemented() + } +} \ No newline at end of file diff --git a/android/src/main/kotlin/me/yohom/foundation_fluttify/android/content/IntentFilterHandler.kt b/android/src/main/kotlin/me/yohom/foundation_fluttify/android/content/IntentFilterHandler.kt new file mode 100644 index 0000000..06ec82f --- /dev/null +++ b/android/src/main/kotlin/me/yohom/foundation_fluttify/android/content/IntentFilterHandler.kt @@ -0,0 +1,18 @@ +package me.yohom.foundation_fluttify.android.content + +import android.content.IntentFilter +import io.flutter.plugin.common.MethodChannel +import me.yohom.foundation_fluttify.core.get + +fun IntentFilterHandler(method: String, rawArgs: Any, methodResult: MethodChannel.Result) { + when (method) { + "android.content.IntentFilter::create" -> { + val action = rawArgs["action"] as String + + val intentFilter = IntentFilter(action) + + methodResult.success(intentFilter) + } + else -> methodResult.notImplemented() + } +} \ No newline at end of file diff --git a/android/src/main/kotlin/me/yohom/foundation_fluttify/android/content/IntentHandler.kt b/android/src/main/kotlin/me/yohom/foundation_fluttify/android/content/IntentHandler.kt new file mode 100644 index 0000000..6fb9cbc --- /dev/null +++ b/android/src/main/kotlin/me/yohom/foundation_fluttify/android/content/IntentHandler.kt @@ -0,0 +1,31 @@ +package me.yohom.foundation_fluttify.android.content + +import android.content.Intent +import android.os.Bundle +import io.flutter.plugin.common.MethodChannel +import me.yohom.foundation_fluttify.core.__this__ + +fun IntentHandler(method: String, args: Any, methodResult: MethodChannel.Result) { + when (method) { + "android.content.Intent::getBundle" -> { + val intent: Intent = args.__this__() + + val bundle = intent.extras ?: Bundle.EMPTY + + val result: MutableMap = mutableMapOf() + for (key in bundle.keySet()) { + result[key] = bundle.getSerializable(key) + } + + methodResult.success(result) + } + "android.content.Intent::getAction" -> { + val intent: Intent = args.__this__() + + val action = intent.action + + methodResult.success(action) + } + else -> methodResult.notImplemented() + } +} \ No newline at end of file diff --git a/android/src/main/kotlin/me/yohom/foundation_fluttify/android/graphics/BitmapHandler.kt b/android/src/main/kotlin/me/yohom/foundation_fluttify/android/graphics/BitmapHandler.kt new file mode 100644 index 0000000..4dcd5a8 --- /dev/null +++ b/android/src/main/kotlin/me/yohom/foundation_fluttify/android/graphics/BitmapHandler.kt @@ -0,0 +1,57 @@ +package me.yohom.foundation_fluttify.android.graphics + +import android.app.Activity +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import io.flutter.plugin.common.MethodChannel +import me.yohom.foundation_fluttify.core.__this__ +import me.yohom.foundation_fluttify.core.get +import java.io.ByteArrayOutputStream + +fun BitmapHandler(method: String, rawArgs: Any, methodResult: MethodChannel.Result, activity: Activity?) { + when (method) { + "android.graphics.Bitmap::create" -> { + val bitmapBytes = rawArgs["bitmapBytes"] as ByteArray + val bitmap = BitmapFactory.decodeByteArray(bitmapBytes, 0, bitmapBytes.size) + + methodResult.success(bitmap) + } + "android.graphics.Bitmap::createWithDrawable" -> { + val drawableId = rawArgs["drawableId"] as Int + if (activity != null) { + val bitmap = BitmapFactory.decodeResource(activity.resources, drawableId) + methodResult.success(bitmap) + } else { + methodResult.error("Activity不能为null", "Activity不能为null", "Activity不能为null") + } + } + "android.graphics.Bitmap::create_batch" -> { + val typedArgs = rawArgs as List> + val bitmapBytesBatch = typedArgs.map { it["bitmapBytes"] as ByteArray } + + val resultBatch = bitmapBytesBatch + .map { BitmapFactory.decodeByteArray(it, 0, it.size) } + + methodResult.success(resultBatch) + } + "android.graphics.Bitmap::getData" -> { + val bitmap = rawArgs["__this__"] as Bitmap + + val outputStream = ByteArrayOutputStream() + bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream) + methodResult.success(outputStream.toByteArray()) + } + "android.graphics.Bitmap::recycle" -> { + val bitmap: Bitmap = rawArgs.__this__() + + bitmap.recycle() + methodResult.success("success") + } + "android.graphics.Bitmap::isRecycled" -> { + val bitmap: Bitmap = rawArgs.__this__() + + methodResult.success(bitmap.isRecycled) + } + else -> methodResult.notImplemented() + } +} \ No newline at end of file diff --git a/android/src/main/kotlin/me/yohom/foundation_fluttify/android/graphics/PointHandler.kt b/android/src/main/kotlin/me/yohom/foundation_fluttify/android/graphics/PointHandler.kt new file mode 100644 index 0000000..8d2d54e --- /dev/null +++ b/android/src/main/kotlin/me/yohom/foundation_fluttify/android/graphics/PointHandler.kt @@ -0,0 +1,29 @@ +package me.yohom.foundation_fluttify.android.graphics + +import android.graphics.Point +import io.flutter.plugin.common.MethodChannel +import me.yohom.foundation_fluttify.core.__this__ +import me.yohom.foundation_fluttify.core.get + +fun PointHandler(method: String, rawArgs: Any, methodResult: MethodChannel.Result) { + when (method) { + "android.graphics.Point::create" -> { + val x = rawArgs["x"] as Int + val y = rawArgs["y"] as Int + val point = Point(x, y) + + methodResult.success(point) + } + "android.graphics.Point::getX" -> { + val point: Point = rawArgs.__this__() + + methodResult.success(point.x) + } + "android.graphics.Point::getY" -> { + val point: Point = rawArgs.__this__() + + methodResult.success(point.y) + } + else -> methodResult.notImplemented() + } +} \ No newline at end of file diff --git a/android/src/main/kotlin/me/yohom/foundation_fluttify/android/location/LocationHandler.kt b/android/src/main/kotlin/me/yohom/foundation_fluttify/android/location/LocationHandler.kt new file mode 100644 index 0000000..fb8f8a4 --- /dev/null +++ b/android/src/main/kotlin/me/yohom/foundation_fluttify/android/location/LocationHandler.kt @@ -0,0 +1,102 @@ +package me.yohom.foundation_fluttify.android.location + +import android.location.Location +import io.flutter.plugin.common.MethodChannel +import me.yohom.foundation_fluttify.core.__this__ +import me.yohom.foundation_fluttify.core.get + +fun LocationHandler(method: String, rawArgs: Any, methodResult: MethodChannel.Result) { + when (method) { + "android.location.Location::create" -> { + val provider = rawArgs["provider"] as String + + val location = Location(provider) + + methodResult.success(location) + } + "android.location.Location::getLatitude" -> { + val location: Location = rawArgs.__this__() + + methodResult.success(location.latitude) + } + "android.location.Location::getLongitude" -> { + val location: Location = rawArgs.__this__() + + methodResult.success(location.longitude) + } + "android.location.Location::getBearing" -> { + val location: Location = rawArgs.__this__() + + methodResult.success(location.bearing) + } + "android.location.Location::getAltitude" -> { + val location: Location = rawArgs.__this__() + + methodResult.success(location.altitude) + } + "android.location.Location::getAccuracy" -> { + val location: Location = rawArgs.__this__() + + methodResult.success(location.accuracy) + } + "android.location.Location::getSpeed" -> { + val location: Location = rawArgs.__this__() + + methodResult.success(location.speed) + } + "android.location.Location::setLatitude" -> { + val latitude = rawArgs["latitude"] as Double + + val location: Location = rawArgs.__this__() + location.latitude = latitude + + methodResult.success("success") + } + "android.location.Location::setLongitude" -> { + val longitude = rawArgs["longitude"] as Double + + val location: Location = rawArgs.__this__() + + location.longitude = longitude + + methodResult.success("success") + } + "android.location.Location::setBearing" -> { + val bearing = rawArgs["bearing"] as Double + + val location: Location = rawArgs.__this__() + + location.bearing = bearing.toFloat() + + methodResult.success("success") + } + "android.location.Location::setAltitude" -> { + val altitude = rawArgs["altitude"] as Double + + val location: Location = rawArgs.__this__() + + location.altitude = altitude + + methodResult.success("success") + } + "android.location.Location::setAccuracy" -> { + val accuracy = rawArgs["accuracy"] as Double + + val location: Location = rawArgs.__this__() + + location.accuracy = accuracy.toFloat() + + methodResult.success("success") + } + "android.location.Location::setSpeed" -> { + val speed = rawArgs["speed"] as Double + + val location: Location = rawArgs.__this__() + + location.speed = speed.toFloat() + + methodResult.success("success") + } + else -> methodResult.notImplemented() + } +} \ No newline at end of file diff --git a/android/src/main/kotlin/me/yohom/foundation_fluttify/android/os/BundleHandler.kt b/android/src/main/kotlin/me/yohom/foundation_fluttify/android/os/BundleHandler.kt new file mode 100644 index 0000000..fe557fa --- /dev/null +++ b/android/src/main/kotlin/me/yohom/foundation_fluttify/android/os/BundleHandler.kt @@ -0,0 +1,75 @@ +package me.yohom.foundation_fluttify.android.os + +import android.os.Bundle +import io.flutter.plugin.common.MethodChannel +import me.yohom.foundation_fluttify.core.__this__ +import me.yohom.foundation_fluttify.core.get + +fun BundleHandler(method: String, rawArgs: Any, methodResult: MethodChannel.Result) { + when (method) { + "android.os.Bundle::create" -> { + val target = Bundle() + methodResult.success(target) + } + "android.os.Bundle::putString" -> { + val key = rawArgs["key"] as String + val value = rawArgs["value"] as String + + val bundle: Bundle = rawArgs.__this__() + + bundle.putString(key, value) + + methodResult.success("success") + } + "android.os.Bundle::putInt" -> { + val key = rawArgs["key"] as String + val value = rawArgs["value"] as Int + + val bundle: Bundle = rawArgs.__this__() + + bundle.putInt(key, value) + + methodResult.success("success") + } + "android.os.Bundle::getString" -> { + val key = rawArgs["key"] as String + + val bundle: Bundle = rawArgs.__this__() + + methodResult.success(bundle.getString(key)) + } + "android.os.Bundle::getInt" -> { + val key = rawArgs["key"] as String + + val bundle: Bundle = rawArgs.__this__() + + methodResult.success(bundle.getInt(key)) + } + "android.os.Bundle::getFloat" -> { + val key = rawArgs["key"] as String + + val bundle: Bundle = rawArgs.__this__() + + methodResult.success(bundle.getFloat(key)) + } + "android.os.Bundle::getDouble" -> { + val key = rawArgs["key"] as String + + val bundle: Bundle = rawArgs.__this__() + + methodResult.success(bundle.getDouble(key)) + } + "android.os.Bundle::getAll" -> { + val bundle: Bundle = rawArgs.__this__() + + val result: MutableMap = mutableMapOf() + + for (item in bundle.keySet()) { + result[item] = bundle.get(item) + } + + methodResult.success(result) + } + else -> methodResult.notImplemented() + } +} \ No newline at end of file diff --git a/android/src/main/kotlin/me/yohom/foundation_fluttify/android/util/PairHandler.kt b/android/src/main/kotlin/me/yohom/foundation_fluttify/android/util/PairHandler.kt new file mode 100644 index 0000000..65ae9a8 --- /dev/null +++ b/android/src/main/kotlin/me/yohom/foundation_fluttify/android/util/PairHandler.kt @@ -0,0 +1,21 @@ +package me.yohom.foundation_fluttify.android.util + +import android.util.Pair +import io.flutter.plugin.common.MethodChannel +import me.yohom.foundation_fluttify.core.__this__ + +fun PairHandler(method: String, rawArgs: Any, methodResult: MethodChannel.Result) { + when (method) { + "android.util.Pair::getFirst" -> { + val pair: Pair<*, *> = rawArgs.__this__() + + methodResult.success(pair.first) + } + "android.util.Pair::getSecond" -> { + val pair: Pair<*, *> = rawArgs.__this__() + + methodResult.success(pair.second) + } + else -> methodResult.notImplemented() + } +} \ No newline at end of file diff --git a/android/src/main/kotlin/me/yohom/foundation_fluttify/android/view/SurfaceHolderHandler.kt b/android/src/main/kotlin/me/yohom/foundation_fluttify/android/view/SurfaceHolderHandler.kt new file mode 100644 index 0000000..a786a78 --- /dev/null +++ b/android/src/main/kotlin/me/yohom/foundation_fluttify/android/view/SurfaceHolderHandler.kt @@ -0,0 +1,75 @@ +package me.yohom.foundation_fluttify.android.view + +import android.view.SurfaceHolder +import io.flutter.plugin.common.BinaryMessenger +import io.flutter.plugin.common.MethodChannel +import me.yohom.foundation_fluttify.core.get + +fun SurfaceHolderHandler( + messenger: BinaryMessenger?, + method: String, + rawArgs: Any, + methodResult: MethodChannel.Result +) { + when (method) { + "android.view.SurfaceHolder::addCallback" -> { + val __this__ = rawArgs["__this__"] as SurfaceHolder + + __this__.addCallback(object : SurfaceHolder.Callback { + private val channel = + MethodChannel(messenger!!, "android.view.SurfaceHolder::addCallback::Callback") + + override fun surfaceCreated(p0: SurfaceHolder) { + print("kotlin: onSurfaceCreated") + channel.invokeMethod( + "Callback::android.view.SurfaceHolder.Callback::surfaceCreated", + mapOf("var1" to p0) + ) + } + + override fun surfaceChanged(p0: SurfaceHolder, p1: Int, p2: Int, p3: Int) { + print("kotlin: surfaceChanged") + channel.invokeMethod( + "Callback::android.view.SurfaceHolder.Callback::surfaceChanged", + mapOf("var1" to p0, "var2" to p1, "var3" to p2, "var4" to p3) + ) + } + + override fun surfaceDestroyed(p0: SurfaceHolder) { + print("kotlin: surfaceDestroyed") + channel.invokeMethod( + "Callback::android.view.SurfaceHolder.Callback::surfaceDestroyed", + mapOf("var1" to p0) + ) + } + +// override fun surfaceCreated(p0: SurfaceHolder) { +// print("kotlin: onSurfaceCreated") +// channel.invokeMethod( +// "Callback::android.view.SurfaceHolder.Callback::surfaceCreated", +// mapOf("var1" to p0) +// ) +// } +// +// override fun surfaceChanged(p0: SurfaceHolder, p1: Int, p2: Int, p3: Int) { +// print("kotlin: surfaceChanged") +// channel.invokeMethod( +// "Callback::android.view.SurfaceHolder.Callback::surfaceChanged", +// mapOf("var1" to p0, "var2" to p1, "var3" to p2, "var4" to p3) +// ) +// } +// +// override fun surfaceDestroyed(p0: SurfaceHolder) { +// print("kotlin: surfaceDestroyed") +// channel.invokeMethod( +// "Callback::android.view.SurfaceHolder.Callback::surfaceDestroyed", +// mapOf("var1" to p0) +// ) +// } + }) + + methodResult.success("success") + } + else -> methodResult.notImplemented() + } +} \ No newline at end of file diff --git a/android/src/main/kotlin/me/yohom/foundation_fluttify/android/view/SurfaceViewHandler.kt b/android/src/main/kotlin/me/yohom/foundation_fluttify/android/view/SurfaceViewHandler.kt new file mode 100644 index 0000000..59c97ba --- /dev/null +++ b/android/src/main/kotlin/me/yohom/foundation_fluttify/android/view/SurfaceViewHandler.kt @@ -0,0 +1,25 @@ +package me.yohom.foundation_fluttify.android.view + +import android.view.SurfaceView +import io.flutter.plugin.common.MethodChannel +import me.yohom.foundation_fluttify.core.get + +fun SurfaceViewHandler(method: String, rawArgs: Any, methodResult: MethodChannel.Result) { + when (method) { + "android.view.SurfaceView::getHolder" -> { + val __this__ = rawArgs["__this__"] as SurfaceView + methodResult.success(__this__.holder) + } + "android.view.SurfaceView::setZOrderOnTop" -> { + val __this__ = rawArgs["__this__"] as SurfaceView + __this__.setZOrderOnTop(rawArgs["onTop"] as Boolean) + methodResult.success("success") + } + "android.view.SurfaceView::setZOrderMediaOverlay" -> { + val __this__ = rawArgs["__this__"] as SurfaceView + __this__.setZOrderMediaOverlay(rawArgs["isMediaOverlay"] as Boolean) + methodResult.success("success") + } + else -> methodResult.notImplemented() + } +} \ No newline at end of file diff --git a/android/src/main/kotlin/me/yohom/foundation_fluttify/android/view/ViewGroupHandler.kt b/android/src/main/kotlin/me/yohom/foundation_fluttify/android/view/ViewGroupHandler.kt new file mode 100644 index 0000000..045d0a8 --- /dev/null +++ b/android/src/main/kotlin/me/yohom/foundation_fluttify/android/view/ViewGroupHandler.kt @@ -0,0 +1,28 @@ +package me.yohom.foundation_fluttify.android.view + +import android.view.View +import android.view.ViewGroup +import io.flutter.plugin.common.MethodChannel +import me.yohom.foundation_fluttify.core.__this__ +import me.yohom.foundation_fluttify.core.get + +fun ViewGroupHandler(method: String, rawArgs: Any, methodResult: MethodChannel.Result) { + when (method) { + "android.view.ViewGroup::addView" -> { + val viewGroup: ViewGroup = rawArgs.__this__() + val child: View = rawArgs["child"] as View + + viewGroup.addView(child) + + methodResult.success("success") + } + "android.view.ViewGroup::removeAllViews" -> { + val viewGroup: ViewGroup = rawArgs.__this__() + + viewGroup.removeAllViews() + + methodResult.success("success") + } + else -> methodResult.notImplemented() + } +} \ No newline at end of file diff --git a/android/src/main/kotlin/me/yohom/foundation_fluttify/android/view/ViewHandler.kt b/android/src/main/kotlin/me/yohom/foundation_fluttify/android/view/ViewHandler.kt new file mode 100644 index 0000000..2fe105d --- /dev/null +++ b/android/src/main/kotlin/me/yohom/foundation_fluttify/android/view/ViewHandler.kt @@ -0,0 +1,9 @@ +package me.yohom.foundation_fluttify.android.view + +import io.flutter.plugin.common.MethodChannel + +fun ViewHandler(method: String, rawArgs: Any, methodResult: MethodChannel.Result) { + when (method) { + else -> methodResult.notImplemented() + } +} \ No newline at end of file diff --git a/android/src/main/kotlin/me/yohom/foundation_fluttify/android/widget/ImageViewHandler.kt b/android/src/main/kotlin/me/yohom/foundation_fluttify/android/widget/ImageViewHandler.kt new file mode 100644 index 0000000..f9087c6 --- /dev/null +++ b/android/src/main/kotlin/me/yohom/foundation_fluttify/android/widget/ImageViewHandler.kt @@ -0,0 +1,32 @@ +package me.yohom.foundation_fluttify.android.widget + +import android.app.Activity +import android.graphics.Bitmap +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import io.flutter.plugin.common.MethodChannel +import me.yohom.foundation_fluttify.core.__this__ +import me.yohom.foundation_fluttify.core.get + +fun ImageViewHandler( + method: String, + rawArgs: Any, + methodResult: MethodChannel.Result, + context: Activity? +) { + when (method) { + "android.widget.ImageView::createWithBitmap" -> { + if (context == null) { + methodResult.error("activity cannot be null", "activity cannot be null", "activity cannot be null") + } else { + val bitmap = rawArgs["bitmap"] as Bitmap + val imageView = ImageView(context) + imageView.setImageBitmap(bitmap) + + methodResult.success(imageView) + } + } + else -> methodResult.notImplemented() + } +} \ No newline at end of file diff --git a/android/src/main/kotlin/me/yohom/foundation_fluttify/core/AnyX.kt b/android/src/main/kotlin/me/yohom/foundation_fluttify/core/AnyX.kt new file mode 100644 index 0000000..a3ebbd8 --- /dev/null +++ b/android/src/main/kotlin/me/yohom/foundation_fluttify/core/AnyX.kt @@ -0,0 +1,11 @@ +@file:Suppress("ObjectPropertyName", "FunctionName") + +package me.yohom.foundation_fluttify.core + +fun Any.__this__(): T { + return (this as Map)["__this__"] as T +} + +operator fun Any.get(key: String): Any? { + return (this as Map)[key] +} diff --git a/android/src/main/kotlin/me/yohom/foundation_fluttify/core/PlatformService.kt b/android/src/main/kotlin/me/yohom/foundation_fluttify/core/PlatformService.kt new file mode 100644 index 0000000..8b88f5b --- /dev/null +++ b/android/src/main/kotlin/me/yohom/foundation_fluttify/core/PlatformService.kt @@ -0,0 +1,181 @@ +@file:Suppress("LocalVariableName", "FunctionName") + +package me.yohom.foundation_fluttify.core + +import android.app.Activity +import android.content.Intent +import android.util.Log +import io.flutter.embedding.engine.plugins.FlutterPlugin +import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding +import io.flutter.plugin.common.MethodChannel +import io.flutter.plugin.common.PluginRegistry +import me.yohom.foundation_fluttify.HEAP +import me.yohom.foundation_fluttify.STACK +import me.yohom.foundation_fluttify.enableLog + +fun PlatformService( + method: String, + args: Map, + methodResult: MethodChannel.Result, + activityBinding: ActivityPluginBinding?, + pluginBinding: FlutterPlugin.FlutterPluginBinding?, + registrar: PluginRegistry.Registrar? +) { + when (method) { + "PlatformService::enableLog" -> { + enableLog = args["enable"] as Boolean + methodResult.success("success") + } + "PlatformService::release" -> { + if (enableLog) Log.d("PlatformService", "size: ${HEAP.size}, 释放对象: ${args["__this__"]}") + + HEAP.remove(args["__this__"]) + + methodResult.success("success") + + // print current HEAP + if (enableLog) Log.d("PlatformService", "size: ${HEAP.size}, HEAP: $HEAP") + } + "PlatformService::isNull" -> { + methodResult.success(args["__this__"] == null) + } + "PlatformService::release_batch" -> { + if (enableLog) Log.d("PlatformService", "size: ${HEAP.size}, 批量释放对象: __this_batch__: ${args["__this_batch__"]}") + + (args["__this_batch__"] as List<*>).forEach { HEAP.remove(it) } + + methodResult.success("success") + + // print current HEAP + if (enableLog) Log.d("PlatformService", "size: ${HEAP.size}, HEAP: $HEAP") + } + "PlatformService::clearHeap" -> { + if (enableLog) Log.d("PlatformService", "size: ${HEAP.size}, CLEAR HEAP") + + HEAP.clear() + methodResult.success("success") + + // print current HEAP + if (enableLog) Log.d("PlatformService", "size: ${HEAP.size}, HEAP: $HEAP") + } + "PlatformService::pushStack" -> { + val name = args["name"] as String + val __this__ = args["__this__"] as Any + + if (enableLog) Log.d("PlatformService", "PUSH OBJECT: $__this__") + + STACK[name] = __this__ + + methodResult.success("success") + + // print current STACK + if (enableLog) Log.d("PlatformService", "size: ${STACK.size}, STACK: $STACK") + } + "PlatformService::pushStackJsonable" -> { + val name = args["name"] as String + val data = args["data"] + + if (enableLog) Log.d("PlatformService", "压入jsonable: ${data?.javaClass}@${data}") + + STACK[name] = data!! + + methodResult.success("success") + + // 打印当前STACK + if (enableLog) Log.d("PlatformService", "size: ${STACK.size}, STACK: $STACK") + } + "PlatformService::clearStack" -> { + STACK.clear() + + methodResult.success("success") + + // print current STACK + if (enableLog) Log.d("PlatformService", "size: ${STACK.size}, STACK: $STACK") + + } + "PlatformService::startActivity" -> { + val activity = activityBinding?.activity + + if (activity != null) { + val activityClass = args["activityClass"] as String + val extras = args["extras"] as Map + + val intent = Intent(activity, Class.forName(activityClass)) + extras.forEach { + when (it.value) { + is String -> intent.putExtra(it.key, it.value as String) + is Int -> intent.putExtra(it.key, it.value as Int) + is Long -> intent.putExtra(it.key, it.value as Long) + is Double -> intent.putExtra(it.key, it.value as Double) + } + } + activity.startActivity(intent) + + methodResult.success("success") + } else { + methodResult.error("当前Activity为null", "当前Activity为null", "当前Activity为null") + } + } + "PlatformService::startActivityForResult" -> { + val activity = activityBinding?.activity + + if (activity != null) { + val activityClass = args["activityClass"] as String + val requestCode = args["requestCode"] as Int + val extras = args["extras"] as Map + + val intent = Intent(activity, Class.forName(activityClass)) + extras.forEach { + when (it.value) { + is String -> intent.putExtra(it.key, it.value as String) + is Int -> intent.putExtra(it.key, it.value as Int) + is Long -> intent.putExtra(it.key, it.value as Long) + is Double -> intent.putExtra(it.key, it.value as Double) + } + } + activity.startActivityForResult(intent, requestCode) + activityBinding.addActivityResultListener { reqCode, resultCode, data -> + if (reqCode == requestCode) { + if (resultCode == Activity.RESULT_OK) { + methodResult.success(data) + } else { + methodResult.error("获取Activity结果失败", "获取Activity结果失败", "获取Activity结果失败") + } + } else { + methodResult.error("非当前请求的响应", "非当前请求的响应", "非当前请求的响应") + } + true + } + + methodResult.success("success") + } else { + methodResult.error("当前Activity为null", "当前Activity为null", "当前Activity为null") + } + } + "PlatformService::getAssetPath" -> { + val activity = activityBinding?.activity + + val flutterAssetPath = args["flutterAssetPath"] as String + + if (activity != null) { + val path = registrar?.lookupKeyForAsset(flutterAssetPath) + ?: pluginBinding?.flutterAssets?.getAssetFilePathByName(flutterAssetPath) + methodResult.success(path) + } else { + methodResult.error("非当前请求的响应", "非当前请求的响应", "非当前请求的响应") + } + } + "PlatformService::viewId2RefId" -> { + val viewId = args["viewId"] as String + + if (HEAP.containsKey(viewId)) { + methodResult.success(System.identityHashCode(HEAP[viewId]).toString()) + // 转换后删除viewId + HEAP.remove(viewId) + } else { + methodResult.error("viewId无对应对象", "viewId无对应对象", "viewId无对应对象") + } + } + else -> methodResult.notImplemented() + } +} \ No newline at end of file diff --git a/android/src/main/kotlin/me/yohom/foundation_fluttify/java/io/FileHandler.kt b/android/src/main/kotlin/me/yohom/foundation_fluttify/java/io/FileHandler.kt new file mode 100644 index 0000000..56dbac7 --- /dev/null +++ b/android/src/main/kotlin/me/yohom/foundation_fluttify/java/io/FileHandler.kt @@ -0,0 +1,17 @@ +package me.yohom.foundation_fluttify.java.io + +import io.flutter.plugin.common.MethodChannel +import me.yohom.foundation_fluttify.core.get +import java.io.File + +fun FileHandler(method: String, rawArgs: Any, methodResult: MethodChannel.Result) { + when (method) { + "java.io.File::create" -> { + val path = rawArgs["path"] as String + val file = File(path) + + methodResult.success(file) + } + else -> methodResult.notImplemented() + } +} \ No newline at end of file diff --git a/android/src/main/kotlin/me/yohom/foundation_fluttify/platform_view/android_opengl_GLSurfaceViewFactory.kt b/android/src/main/kotlin/me/yohom/foundation_fluttify/platform_view/android_opengl_GLSurfaceViewFactory.kt new file mode 100644 index 0000000..f014571 --- /dev/null +++ b/android/src/main/kotlin/me/yohom/foundation_fluttify/platform_view/android_opengl_GLSurfaceViewFactory.kt @@ -0,0 +1,27 @@ +package me.yohom.foundation_fluttify.platform_view + +import android.content.Context +import android.opengl.GLSurfaceView +import android.view.View +import io.flutter.plugin.common.StandardMessageCodec +import io.flutter.plugin.platform.PlatformView +import io.flutter.plugin.platform.PlatformViewFactory +import me.yohom.foundation_fluttify.HEAP + +@Suppress("ClassName") +class android_opengl_GLSurfaceViewFactory : PlatformViewFactory(StandardMessageCodec.INSTANCE) { + override fun create(context: Context?, id: Int, params: Any?): PlatformView { + val view = GLSurfaceView(context) + + // 同时存放viewId和refId的对象, 供后续viewId转refId使用 + HEAP[(Int.MAX_VALUE - id).toString()] = view + HEAP["android.opengl.GLSurfaceView:${System.identityHashCode(view)}"] = view + return object : PlatformView { + override fun getView(): View { + return view + } + + override fun dispose() {} + } + } +} diff --git a/android/src/main/kotlin/me/yohom/foundation_fluttify/platform_view/android_view_SurfaceViewFactory.kt b/android/src/main/kotlin/me/yohom/foundation_fluttify/platform_view/android_view_SurfaceViewFactory.kt new file mode 100644 index 0000000..1468892 --- /dev/null +++ b/android/src/main/kotlin/me/yohom/foundation_fluttify/platform_view/android_view_SurfaceViewFactory.kt @@ -0,0 +1,61 @@ +package me.yohom.foundation_fluttify.platform_view + +import android.content.Context +import android.view.SurfaceHolder +import android.view.SurfaceView +import android.view.View +import io.flutter.plugin.common.BinaryMessenger +import io.flutter.plugin.common.MethodChannel +import io.flutter.plugin.common.StandardMethodCodec +import io.flutter.plugin.platform.PlatformView +import io.flutter.plugin.platform.PlatformViewFactory +import me.yohom.foundation_fluttify.HEAP +import me.yohom.foundation_fluttify.core.FluttifyMessageCodec + +@Suppress("ClassName") +class android_view_SurfaceViewFactory(private val binaryMessenger: BinaryMessenger?) + : PlatformViewFactory(FluttifyMessageCodec()) { + override fun create(context: Context?, id: Int, params: Any?): PlatformView { + val view = SurfaceView(context) + + view.holder.addCallback(object : SurfaceHolder.Callback { + private val channel = MethodChannel( + binaryMessenger!!, + "android.view.SurfaceHolder::addCallback::Callback", + StandardMethodCodec(FluttifyMessageCodec()) + ) + + override fun surfaceCreated(holder: SurfaceHolder) { + channel.invokeMethod( + "Callback::android.view.SurfaceHolder.Callback::surfaceCreated", + mapOf("holder" to holder) + ) + } + + override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) { + channel.invokeMethod( + "Callback::android.view.SurfaceHolder.Callback::surfaceChanged", + mapOf("holder" to holder, "format" to format, "width" to width, "height" to height) + ) + } + + override fun surfaceDestroyed(holder: SurfaceHolder) { + channel.invokeMethod( + "Callback::android.view.SurfaceHolder.Callback::surfaceDestroyed", + mapOf("holder" to holder) + ) + } + }) + + // 同时存放viewId和refId的对象, 供后续viewId转refId使用 + HEAP[(Int.MAX_VALUE - id).toString()] = view + HEAP["android.view.SurfaceView:${System.identityHashCode(view)}"] = view + return object : PlatformView { + override fun getView(): View { + return view + } + + override fun dispose() {} + } + } +} diff --git a/android/src/main/kotlin/me/yohom/foundation_fluttify/platform_view/android_widget_FrameLayoutFactory.kt b/android/src/main/kotlin/me/yohom/foundation_fluttify/platform_view/android_widget_FrameLayoutFactory.kt new file mode 100644 index 0000000..31f3115 --- /dev/null +++ b/android/src/main/kotlin/me/yohom/foundation_fluttify/platform_view/android_widget_FrameLayoutFactory.kt @@ -0,0 +1,27 @@ +package me.yohom.foundation_fluttify.platform_view + +import android.content.Context +import android.view.View +import android.widget.FrameLayout +import io.flutter.plugin.platform.PlatformView +import io.flutter.plugin.platform.PlatformViewFactory +import me.yohom.foundation_fluttify.HEAP +import me.yohom.foundation_fluttify.core.FluttifyMessageCodec + +@Suppress("ClassName") +class android_widget_FrameLayoutFactory : PlatformViewFactory(FluttifyMessageCodec()) { + override fun create(context: Context?, id: Int, params: Any?): PlatformView { + val view = FrameLayout(context!!) + + // 同时存放viewId和refId的对象, 供后续viewId转refId使用 + HEAP[(Int.MAX_VALUE - id).toString()] = view + HEAP["android.widget.FrameLayout:${System.identityHashCode(view)}"] = view + return object : PlatformView { + override fun getView(): View { + return view + } + + override fun dispose() {} + } + } +} diff --git a/example/.gitignore b/example/.gitignore new file mode 100644 index 0000000..29a3a50 --- /dev/null +++ b/example/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# 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 +.pub-cache/ +.pub/ +/build/ + +# 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/example/README.md b/example/README.md new file mode 100644 index 0000000..50d36c8 --- /dev/null +++ b/example/README.md @@ -0,0 +1,16 @@ +# foundation_fluttify_example + +Demonstrates how to use the foundation_fluttify 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/example/android/.gradle/7.4/checksums/checksums.lock b/example/android/.gradle/7.4/checksums/checksums.lock new file mode 100644 index 0000000..a70ae14 Binary files /dev/null and b/example/android/.gradle/7.4/checksums/checksums.lock differ diff --git a/example/android/.gradle/7.4/dependencies-accessors/dependencies-accessors.lock b/example/android/.gradle/7.4/dependencies-accessors/dependencies-accessors.lock new file mode 100644 index 0000000..6c66c91 Binary files /dev/null and b/example/android/.gradle/7.4/dependencies-accessors/dependencies-accessors.lock differ diff --git a/example/android/.gradle/7.4/dependencies-accessors/gc.properties b/example/android/.gradle/7.4/dependencies-accessors/gc.properties new file mode 100644 index 0000000..e69de29 diff --git a/example/android/.gradle/7.4/fileChanges/last-build.bin b/example/android/.gradle/7.4/fileChanges/last-build.bin new file mode 100644 index 0000000..f76dd23 Binary files /dev/null and b/example/android/.gradle/7.4/fileChanges/last-build.bin differ diff --git a/example/android/.gradle/7.4/fileHashes/fileHashes.lock b/example/android/.gradle/7.4/fileHashes/fileHashes.lock new file mode 100644 index 0000000..a2702a9 Binary files /dev/null and b/example/android/.gradle/7.4/fileHashes/fileHashes.lock differ diff --git a/example/android/.gradle/7.4/gc.properties b/example/android/.gradle/7.4/gc.properties new file mode 100644 index 0000000..e69de29 diff --git a/example/android/.gradle/8.7/checksums/checksums.lock b/example/android/.gradle/8.7/checksums/checksums.lock new file mode 100644 index 0000000..400254e Binary files /dev/null and b/example/android/.gradle/8.7/checksums/checksums.lock differ diff --git a/example/android/.gradle/8.7/checksums/md5-checksums.bin b/example/android/.gradle/8.7/checksums/md5-checksums.bin new file mode 100644 index 0000000..eff26f2 Binary files /dev/null and b/example/android/.gradle/8.7/checksums/md5-checksums.bin differ diff --git a/example/android/.gradle/8.7/checksums/sha1-checksums.bin b/example/android/.gradle/8.7/checksums/sha1-checksums.bin new file mode 100644 index 0000000..32dc49f Binary files /dev/null and b/example/android/.gradle/8.7/checksums/sha1-checksums.bin differ diff --git a/example/android/.gradle/8.7/dependencies-accessors/gc.properties b/example/android/.gradle/8.7/dependencies-accessors/gc.properties new file mode 100644 index 0000000..e69de29 diff --git a/example/android/.gradle/8.7/executionHistory/executionHistory.bin b/example/android/.gradle/8.7/executionHistory/executionHistory.bin new file mode 100644 index 0000000..e80b0be Binary files /dev/null and b/example/android/.gradle/8.7/executionHistory/executionHistory.bin differ diff --git a/example/android/.gradle/8.7/executionHistory/executionHistory.lock b/example/android/.gradle/8.7/executionHistory/executionHistory.lock new file mode 100644 index 0000000..9989be4 Binary files /dev/null and b/example/android/.gradle/8.7/executionHistory/executionHistory.lock differ diff --git a/example/android/.gradle/8.7/fileChanges/last-build.bin b/example/android/.gradle/8.7/fileChanges/last-build.bin new file mode 100644 index 0000000..f76dd23 Binary files /dev/null and b/example/android/.gradle/8.7/fileChanges/last-build.bin differ diff --git a/example/android/.gradle/8.7/fileHashes/fileHashes.bin b/example/android/.gradle/8.7/fileHashes/fileHashes.bin new file mode 100644 index 0000000..fc035f2 Binary files /dev/null and b/example/android/.gradle/8.7/fileHashes/fileHashes.bin differ diff --git a/example/android/.gradle/8.7/fileHashes/fileHashes.lock b/example/android/.gradle/8.7/fileHashes/fileHashes.lock new file mode 100644 index 0000000..9896ed7 Binary files /dev/null and b/example/android/.gradle/8.7/fileHashes/fileHashes.lock differ diff --git a/example/android/.gradle/8.7/fileHashes/resourceHashesCache.bin b/example/android/.gradle/8.7/fileHashes/resourceHashesCache.bin new file mode 100644 index 0000000..401bdfd Binary files /dev/null and b/example/android/.gradle/8.7/fileHashes/resourceHashesCache.bin differ diff --git a/example/android/.gradle/8.7/gc.properties b/example/android/.gradle/8.7/gc.properties new file mode 100644 index 0000000..e69de29 diff --git a/example/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/example/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock new file mode 100644 index 0000000..b917857 Binary files /dev/null and b/example/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock differ diff --git a/example/android/.gradle/buildOutputCleanup/cache.properties b/example/android/.gradle/buildOutputCleanup/cache.properties new file mode 100644 index 0000000..c3cbf35 --- /dev/null +++ b/example/android/.gradle/buildOutputCleanup/cache.properties @@ -0,0 +1,2 @@ +#Sun Nov 17 00:00:14 CST 2024 +gradle.version=8.7 diff --git a/example/android/.gradle/buildOutputCleanup/outputFiles.bin b/example/android/.gradle/buildOutputCleanup/outputFiles.bin new file mode 100644 index 0000000..59c8e62 Binary files /dev/null and b/example/android/.gradle/buildOutputCleanup/outputFiles.bin differ diff --git a/example/android/.gradle/file-system.probe b/example/android/.gradle/file-system.probe new file mode 100644 index 0000000..802ed69 Binary files /dev/null and b/example/android/.gradle/file-system.probe differ diff --git a/example/android/.gradle/noVersion/buildLogic.lock b/example/android/.gradle/noVersion/buildLogic.lock new file mode 100644 index 0000000..4d32014 Binary files /dev/null and b/example/android/.gradle/noVersion/buildLogic.lock differ diff --git a/example/android/.gradle/vcs-1/gc.properties b/example/android/.gradle/vcs-1/gc.properties new file mode 100644 index 0000000..e69de29 diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle new file mode 100644 index 0000000..5b1c29e --- /dev/null +++ b/example/android/app/build.gradle @@ -0,0 +1,43 @@ +plugins { + id "com.android.application" + id "kotlin-android" + // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. + id "dev.flutter.flutter-gradle-plugin" +} + +android { + namespace = "me.yohom.foundation_fluttify_example" + compileSdk = flutter.compileSdkVersion + ndkVersion = flutter.ndkVersion + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = JavaVersion.VERSION_1_8 + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "me.yohom.foundation_fluttify_example" + minSdk = flutter.minSdkVersion + targetSdk = flutter.targetSdkVersion + versionCode = flutter.versionCode + versionName = flutter.versionName + } + + 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 = "../.." +} + diff --git a/example/android/app/src/debug/AndroidManifest.xml b/example/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..cf477bf --- /dev/null +++ b/example/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..abae935 --- /dev/null +++ b/example/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + diff --git a/example/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java b/example/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java new file mode 100644 index 0000000..7cdcd3c --- /dev/null +++ b/example/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java @@ -0,0 +1,24 @@ +package io.flutter.plugins; + +import androidx.annotation.Keep; +import androidx.annotation.NonNull; +import io.flutter.Log; + +import io.flutter.embedding.engine.FlutterEngine; + +/** + * Generated file. Do not edit. + * This file is generated by the Flutter tool based on the + * plugins that support the Android platform. + */ +@Keep +public final class GeneratedPluginRegistrant { + private static final String TAG = "GeneratedPluginRegistrant"; + public static void registerWith(@NonNull FlutterEngine flutterEngine) { + try { + flutterEngine.getPlugins().add(new me.yohom.foundation_fluttify.FoundationFluttifyPlugin()); + } catch (Exception e) { + Log.e(TAG, "Error registering plugin foundation_fluttify, me.yohom.foundation_fluttify.FoundationFluttifyPlugin", e); + } + } +} diff --git a/example/android/app/src/main/kotlin/me/yohom/foundation_fluttify_example/MainActivity.kt b/example/android/app/src/main/kotlin/me/yohom/foundation_fluttify_example/MainActivity.kt new file mode 100644 index 0000000..a71f092 --- /dev/null +++ b/example/android/app/src/main/kotlin/me/yohom/foundation_fluttify_example/MainActivity.kt @@ -0,0 +1,5 @@ +package me.yohom.foundation_fluttify_example + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() diff --git a/example/android/app/src/main/res/drawable/launch_background.xml b/example/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 0000000..304732f --- /dev/null +++ b/example/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..db77bb4 Binary files /dev/null and b/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..17987b7 Binary files /dev/null and b/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..09d4391 Binary files /dev/null and b/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..d5f1c8d Binary files /dev/null and b/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..4d6372e Binary files /dev/null and b/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/example/android/app/src/main/res/values/styles.xml b/example/android/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..00fa441 --- /dev/null +++ b/example/android/app/src/main/res/values/styles.xml @@ -0,0 +1,8 @@ + + + + diff --git a/example/android/app/src/profile/AndroidManifest.xml b/example/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..cf477bf --- /dev/null +++ b/example/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/example/android/build.gradle b/example/android/build.gradle new file mode 100644 index 0000000..8e9de9d --- /dev/null +++ b/example/android/build.gradle @@ -0,0 +1,18 @@ +allprojects { + repositories { + google() + mavenCentral() + } +} + +rootProject.buildDir = "../build" +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(":app") +} + +tasks.register("clean", Delete) { + delete rootProject.buildDir +} \ No newline at end of file diff --git a/example/android/gradle.properties b/example/android/gradle.properties new file mode 100644 index 0000000..2324ab5 --- /dev/null +++ b/example/android/gradle.properties @@ -0,0 +1,5 @@ +org.gradle.jvmargs=-Xmx1536M + +android.enableR8=true +android.useAndroidX=true +android.enableJetifier=true diff --git a/example/android/gradle/wrapper/gradle-wrapper.jar b/example/android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..13372ae Binary files /dev/null and b/example/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/example/android/gradle/wrapper/gradle-wrapper.properties b/example/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..c2a7878 --- /dev/null +++ b/example/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Mon Nov 04 23:28:03 CST 2024 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/example/android/gradlew b/example/android/gradlew new file mode 100644 index 0000000..9d82f78 --- /dev/null +++ b/example/android/gradlew @@ -0,0 +1,160 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/example/android/gradlew.bat b/example/android/gradlew.bat new file mode 100644 index 0000000..8a0b282 --- /dev/null +++ b/example/android/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/example/android/local.properties b/example/android/local.properties new file mode 100644 index 0000000..de0dd04 --- /dev/null +++ b/example/android/local.properties @@ -0,0 +1,3 @@ +sdk.dir=C:\\Users\\Administrator\\AppData\\Local\\Android\\sdk +flutter.sdk=D:\\futter\\flutter +flutter.buildMode=debug \ No newline at end of file diff --git a/example/android/settings.gradle b/example/android/settings.gradle new file mode 100644 index 0000000..c4278ea --- /dev/null +++ b/example/android/settings.gradle @@ -0,0 +1,25 @@ +pluginManagement { + def flutterSdkPath = { + def properties = new Properties() + file("local.properties").withInputStream { properties.load(it) } + def flutterSdkPath = properties.getProperty("flutter.sdk") + assert flutterSdkPath != null, "flutter.sdk not set in local.properties" + return flutterSdkPath + }() + + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id "dev.flutter.flutter-plugin-loader" version "1.0.0" + id "com.android.application" version '8.6.1' apply false + id "org.jetbrains.kotlin.android" version "1.8.22" apply false +} + +include ":app" diff --git a/example/ios/Flutter/AppFrameworkInfo.plist b/example/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 0000000..f2872cf --- /dev/null +++ b/example/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 9.0 + + diff --git a/example/ios/Flutter/Debug.xcconfig b/example/ios/Flutter/Debug.xcconfig new file mode 100644 index 0000000..e8efba1 --- /dev/null +++ b/example/ios/Flutter/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "Generated.xcconfig" diff --git a/example/ios/Flutter/Generated.xcconfig b/example/ios/Flutter/Generated.xcconfig new file mode 100644 index 0000000..7854552 --- /dev/null +++ b/example/ios/Flutter/Generated.xcconfig @@ -0,0 +1,14 @@ +// This is a generated file; do not edit or check into version control. +FLUTTER_ROOT=D:\futter\flutter +FLUTTER_APPLICATION_PATH=D:\FlutterProjects\foundation_fluttify\example +COCOAPODS_PARALLEL_CODE_SIGN=true +FLUTTER_TARGET=lib\main.dart +FLUTTER_BUILD_DIR=build +FLUTTER_BUILD_NAME=1.0.0 +FLUTTER_BUILD_NUMBER=1 +EXCLUDED_ARCHS[sdk=iphonesimulator*]=i386 +EXCLUDED_ARCHS[sdk=iphoneos*]=armv7 +DART_OBFUSCATION=false +TRACK_WIDGET_CREATION=true +TREE_SHAKE_ICONS=false +PACKAGE_CONFIG=.dart_tool/package_config.json diff --git a/example/ios/Flutter/Release.xcconfig b/example/ios/Flutter/Release.xcconfig new file mode 100644 index 0000000..399e934 --- /dev/null +++ b/example/ios/Flutter/Release.xcconfig @@ -0,0 +1,2 @@ +#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "Generated.xcconfig" diff --git a/example/ios/Flutter/flutter_export_environment.sh b/example/ios/Flutter/flutter_export_environment.sh new file mode 100644 index 0000000..9b490f8 --- /dev/null +++ b/example/ios/Flutter/flutter_export_environment.sh @@ -0,0 +1,13 @@ +#!/bin/sh +# This is a generated file; do not edit or check into version control. +export "FLUTTER_ROOT=D:\futter\flutter" +export "FLUTTER_APPLICATION_PATH=D:\FlutterProjects\foundation_fluttify\example" +export "COCOAPODS_PARALLEL_CODE_SIGN=true" +export "FLUTTER_TARGET=lib\main.dart" +export "FLUTTER_BUILD_DIR=build" +export "FLUTTER_BUILD_NAME=1.0.0" +export "FLUTTER_BUILD_NUMBER=1" +export "DART_OBFUSCATION=false" +export "TRACK_WIDGET_CREATION=true" +export "TREE_SHAKE_ICONS=false" +export "PACKAGE_CONFIG=.dart_tool/package_config.json" diff --git a/example/ios/Podfile b/example/ios/Podfile new file mode 100644 index 0000000..a4af0a9 --- /dev/null +++ b/example/ios/Podfile @@ -0,0 +1,38 @@ +# Uncomment this line to define a global platform for your project +platform :ios, '9.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock new file mode 100644 index 0000000..13d573c --- /dev/null +++ b/example/ios/Podfile.lock @@ -0,0 +1,22 @@ +PODS: + - Flutter (1.0.0) + - foundation_fluttify (0.0.1): + - Flutter + +DEPENDENCIES: + - Flutter (from `Flutter`) + - foundation_fluttify (from `.symlinks/plugins/foundation_fluttify/ios`) + +EXTERNAL SOURCES: + Flutter: + :path: Flutter + foundation_fluttify: + :path: ".symlinks/plugins/foundation_fluttify/ios" + +SPEC CHECKSUMS: + Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a + foundation_fluttify: 0c45145e3fad1fb99188e4979daed5b24cd9b278 + +PODFILE CHECKSUM: b1f7a399522c118a74b177b13c01eca692aa7e6d + +COCOAPODS: 1.11.3 diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000..d2d875a --- /dev/null +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,548 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 83F82D8B4BC87070FC6F6086 /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 04A2AE97B31701B40C7E2282 /* libPods-Runner.a */; }; + 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; }; + 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; + 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 04A2AE97B31701B40C7E2282 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 82B765490BCE9380D3436B41 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + E4E500B2ACB8A3E22A041874 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + FB55EDC5E0BAFFD80DB75218 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 83F82D8B4BC87070FC6F6086 /* libPods-Runner.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 8AAC1AA9A447384D56FB12A0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 04A2AE97B31701B40C7E2282 /* libPods-Runner.a */, + ); + name = Frameworks; + sourceTree = ""; + }; + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + D0DD03BDC642C8B12B3EBAC4 /* Pods */, + 8AAC1AA9A447384D56FB12A0 /* Frameworks */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */, + 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */, + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 97C146F21CF9000F007C117D /* main.m */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + D0DD03BDC642C8B12B3EBAC4 /* Pods */ = { + isa = PBXGroup; + children = ( + 82B765490BCE9380D3436B41 /* Pods-Runner.debug.xcconfig */, + E4E500B2ACB8A3E22A041874 /* Pods-Runner.release.xcconfig */, + FB55EDC5E0BAFFD80DB75218 /* Pods-Runner.profile.xcconfig */, + ); + path = Pods; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 497EC7AEF0CDF08A93D3B46C /* [CP] Check Pods Manifest.lock */, + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1300; + ORGANIZATIONNAME = "The Chromium Authors"; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + DevelopmentTeam = X5P24RK5QW; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 497EC7AEF0CDF08A93D3B46C /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */, + 97C146F31CF9000F007C117D /* main.m in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = X5P24RK5QW; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = me.yohom.foundationFluttifyExample; + PRODUCT_NAME = "$(TARGET_NAME)"; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = X5P24RK5QW; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = me.yohom.foundationFluttifyExample; + PRODUCT_NAME = "$(TARGET_NAME)"; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = X5P24RK5QW; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = me.yohom.foundationFluttifyExample; + PRODUCT_NAME = "$(TARGET_NAME)"; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000..3db53b6 --- /dev/null +++ b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/example/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..21a3cc1 --- /dev/null +++ b/example/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/example/ios/Runner/AppDelegate.h b/example/ios/Runner/AppDelegate.h new file mode 100644 index 0000000..36e21bb --- /dev/null +++ b/example/ios/Runner/AppDelegate.h @@ -0,0 +1,6 @@ +#import +#import + +@interface AppDelegate : FlutterAppDelegate + +@end diff --git a/example/ios/Runner/AppDelegate.m b/example/ios/Runner/AppDelegate.m new file mode 100644 index 0000000..59a72e9 --- /dev/null +++ b/example/ios/Runner/AppDelegate.m @@ -0,0 +1,13 @@ +#include "AppDelegate.h" +#include "GeneratedPluginRegistrant.h" + +@implementation AppDelegate + +- (BOOL)application:(UIApplication *)application + didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + [GeneratedPluginRegistrant registerWithRegistry:self]; + // Override point for customization after application launch. + return [super application:application didFinishLaunchingWithOptions:launchOptions]; +} + +@end diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d36b1fa --- /dev/null +++ b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 0000000..dc9ada4 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 0000000..28c6bf0 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 0000000..2ccbfd9 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000..f091b6b Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 0000000..4cde121 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000..d0ef06e Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100644 index 0000000..dcdc230 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100644 index 0000000..2ccbfd9 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000..c8f9ed8 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 0000000..a6d6b86 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000..a6d6b86 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000..75b2d16 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 0000000..c4df70d Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100644 index 0000000..6a84f41 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 0000000..d0e1f58 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json new file mode 100644 index 0000000..0bedcf2 --- /dev/null +++ b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ diff --git a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ diff --git a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ diff --git a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 0000000..89c2725 --- /dev/null +++ b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/example/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..f2e259c --- /dev/null +++ b/example/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/ios/Runner/Base.lproj/Main.storyboard b/example/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 0000000..f3c2851 --- /dev/null +++ b/example/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/ios/Runner/GeneratedPluginRegistrant.h b/example/ios/Runner/GeneratedPluginRegistrant.h new file mode 100644 index 0000000..7a89092 --- /dev/null +++ b/example/ios/Runner/GeneratedPluginRegistrant.h @@ -0,0 +1,19 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GeneratedPluginRegistrant_h +#define GeneratedPluginRegistrant_h + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface GeneratedPluginRegistrant : NSObject ++ (void)registerWithRegistry:(NSObject*)registry; +@end + +NS_ASSUME_NONNULL_END +#endif /* GeneratedPluginRegistrant_h */ diff --git a/example/ios/Runner/GeneratedPluginRegistrant.m b/example/ios/Runner/GeneratedPluginRegistrant.m new file mode 100644 index 0000000..a8aac52 --- /dev/null +++ b/example/ios/Runner/GeneratedPluginRegistrant.m @@ -0,0 +1,21 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#import "GeneratedPluginRegistrant.h" + +#if __has_include() +#import +#else +@import foundation_fluttify; +#endif + +@implementation GeneratedPluginRegistrant + ++ (void)registerWithRegistry:(NSObject*)registry { + [FoundationFluttifyPlugin registerWithRegistrar:[registry registrarForPlugin:@"FoundationFluttifyPlugin"]]; +} + +@end diff --git a/example/ios/Runner/Info.plist b/example/ios/Runner/Info.plist new file mode 100644 index 0000000..318e43f --- /dev/null +++ b/example/ios/Runner/Info.plist @@ -0,0 +1,47 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + foundation_fluttify_example + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + CADisableMinimumFrameDurationOnPhone + + + diff --git a/example/ios/Runner/main.m b/example/ios/Runner/main.m new file mode 100644 index 0000000..dff6597 --- /dev/null +++ b/example/ios/Runner/main.m @@ -0,0 +1,9 @@ +#import +#import +#import "AppDelegate.h" + +int main(int argc, char* argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/example/lib/main.dart b/example/lib/main.dart new file mode 100644 index 0000000..70a6e09 --- /dev/null +++ b/example/lib/main.dart @@ -0,0 +1,30 @@ +import 'package:flutter/material.dart'; +import 'package:foundation_fluttify/foundation_fluttify.dart'; + +void main() => runApp(MyApp()); + +class MyApp extends StatefulWidget { + @override + _MyAppState createState() => _MyAppState(); +} + +class _MyAppState extends State { + @override + Widget build(BuildContext context) { + return MaterialApp( + home: Scaffold( + appBar: AppBar(title: const Text('Plugin example app')), + ), + ); + } + + Future _testAddProperty() async { + final target = await CGPoint.create(225, 556); + final target1 = await CGPoint.create(112, 556); + await target.addProperty__(1, target1); + + final result = await target.getProperty__(1); + final target1Result = CGPoint()..refId = result.refId; + debugPrint('结果: ${await target1Result.x}'); + } +} diff --git a/example/pubspec.lock b/example/pubspec.lock new file mode 100644 index 0000000..6a64c63 --- /dev/null +++ b/example/pubspec.lock @@ -0,0 +1,204 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + async: + dependency: transitive + description: + name: async + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" + source: hosted + version: "2.11.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + characters: + dependency: transitive + description: + name: characters + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + url: "https://pub.dev" + source: hosted + version: "1.3.0" + clock: + dependency: transitive + description: + name: clock + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" + source: hosted + version: "1.1.1" + collection: + dependency: transitive + description: + name: collection + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + url: "https://pub.dev" + source: hosted + version: "1.18.0" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 + url: "https://pub.dev" + source: hosted + version: "1.0.8" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" + source: hosted + version: "1.3.1" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + foundation_fluttify: + dependency: "direct dev" + description: + path: ".." + relative: true + source: path + version: "0.13.0+1" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" + url: "https://pub.dev" + source: hosted + version: "10.0.5" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" + url: "https://pub.dev" + source: hosted + version: "3.0.5" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + url: "https://pub.dev" + source: hosted + version: "3.0.1" + matcher: + dependency: transitive + description: + name: matcher + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + url: "https://pub.dev" + source: hosted + version: "0.12.16+1" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + url: "https://pub.dev" + source: hosted + version: "0.11.1" + meta: + dependency: transitive + description: + name: meta + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 + url: "https://pub.dev" + source: hosted + version: "1.15.0" + path: + dependency: transitive + description: + name: path + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + url: "https://pub.dev" + source: hosted + version: "1.9.0" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_span: + dependency: transitive + description: + name: source_span + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + url: "https://pub.dev" + source: hosted + version: "1.10.0" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + url: "https://pub.dev" + source: hosted + version: "1.11.1" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + url: "https://pub.dev" + source: hosted + version: "2.1.2" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + test_api: + dependency: transitive + description: + name: test_api + sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" + url: "https://pub.dev" + source: hosted + version: "0.7.2" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" + url: "https://pub.dev" + source: hosted + version: "14.2.5" +sdks: + dart: ">=3.5.3 <4.0.0" + flutter: ">=3.18.0-18.0.pre.54" diff --git a/example/pubspec.yaml b/example/pubspec.yaml new file mode 100644 index 0000000..c93b222 --- /dev/null +++ b/example/pubspec.yaml @@ -0,0 +1,21 @@ +name: foundation_fluttify_example +description: Demonstrates how to use the foundation_fluttify plugin. +publish_to: 'none' + +environment: + sdk: ^3.5.3 + +dependencies: + flutter: + sdk: flutter + cupertino_icons: ^1.0.8 + +dev_dependencies: + flutter_test: + sdk: flutter + + foundation_fluttify: + path: ../ + +flutter: + uses-material-design: true \ No newline at end of file diff --git a/example/test/widget_test.dart b/example/test/widget_test.dart new file mode 100644 index 0000000..a4a99ae --- /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 that Flutter provides. 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:foundation_fluttify_example/main.dart'; + +void main() { + testWidgets('Verify Platform version', (WidgetTester tester) async { + // Build our app and trigger a frame. + await tester.pumpWidget(MyApp()); + + // Verify that platform version is retrieved. + expect( + find.byWidgetPredicate( + (Widget widget) => widget is Text && + widget.data!.startsWith('Running on:'), + ), + findsOneWidget, + ); + }); +} diff --git a/foundation_fluttify-0.13.0+1.tar.gz b/foundation_fluttify-0.13.0+1.tar.gz new file mode 100644 index 0000000..2567f92 Binary files /dev/null and b/foundation_fluttify-0.13.0+1.tar.gz differ diff --git a/ios/Classes/CGPointHandler.h b/ios/Classes/CGPointHandler.h new file mode 100644 index 0000000..523582b --- /dev/null +++ b/ios/Classes/CGPointHandler.h @@ -0,0 +1,12 @@ +// +// Created by Yohom Bao on 2019/11/29. +// + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +void CGPointHandler(NSString* method, id args, FlutterResult methodResult); + +NS_ASSUME_NONNULL_END diff --git a/ios/Classes/CGPointHandler.m b/ios/Classes/CGPointHandler.m new file mode 100644 index 0000000..db494db --- /dev/null +++ b/ios/Classes/CGPointHandler.m @@ -0,0 +1,98 @@ +// +// Created by Yohom Bao on 2019/11/29. +// + +#import +#import "CGPointHandler.h" + +extern BOOL enableLog; + +void CGPointHandler(NSString* method, id rawArgs, FlutterResult methodResult) { + if ([@"CGPoint::getX" isEqualToString:method]) { + NSDictionary* args = (NSDictionary*) rawArgs; + + NSValue *value = (NSValue *) args[@"__this__"]; + if (value != nil && (NSNull*) value != [NSNull null]) { + CGPoint cgPoint = value.CGPointValue; + methodResult(@(cgPoint.x)); + } else { + methodResult([FlutterError errorWithCode:@"目标对象为nul" + message:@"目标对象为nul" + details:@"目标对象为nul"]); + } + } else if ([@"CGPoint::getY" isEqualToString:method]) { + NSDictionary* args = (NSDictionary*) rawArgs; + + NSValue *value = (NSValue *) args[@"__this__"]; + if (value != nil && (NSNull*) value != [NSNull null]) { + CGPoint cgPoint = value.CGPointValue; + methodResult(@(cgPoint.y)); + } else { + methodResult([FlutterError errorWithCode:@"目标对象为nul" + message:@"目标对象为nul" + details:@"目标对象为nul"]); + } + } else if ([@"CGPoint::getX_batch" isEqualToString:method]) { + NSDictionary* args = (NSDictionary*) rawArgs; + + NSArray* value = (NSArray*) args[@"__this__"]; + if (value != nil && (NSNull*) value != [NSNull null]) { + NSMutableArray* result = [NSMutableArray arrayWithCapacity:value.count]; + + for (NSValue* pointValue in value) { + [result addObject:@(pointValue.CGPointValue.x)]; + } + + methodResult(result); + } else { + methodResult([FlutterError errorWithCode:@"目标对象为nul" + message:@"目标对象为nul" + details:@"目标对象为nul"]); + } + } else if ([@"CGPoint::getY_batch" isEqualToString:method]) { + NSDictionary* args = (NSDictionary*) rawArgs; + + NSArray* value = (NSArray*) args[@"__this__"]; + if (value != nil && (NSNull*) value != [NSNull null]) { + NSMutableArray* result = [NSMutableArray arrayWithCapacity:value.count]; + + for (NSValue* pointValue in value) { + [result addObject:@(pointValue.CGPointValue.y)]; + } + + methodResult(result); + } else { + methodResult([FlutterError errorWithCode:@"目标对象为nul" + message:@"目标对象为nul" + details:@"目标对象为nul"]); + } + } else if ([@"CGPoint::create" isEqualToString:method]) { + NSDictionary* args = (NSDictionary*) rawArgs; + + NSNumber *x = (NSNumber *) args[@"x"]; + NSNumber *y = (NSNumber *) args[@"y"]; + + CGPoint cgPoint = CGPointMake([x floatValue], [y floatValue]); + NSValue *valuePoint = [NSValue valueWithCGPoint:cgPoint]; + + methodResult(valuePoint); + } else if ([@"CGPoint::create_batch" isEqualToString:method]) { + NSDictionary* args = (NSDictionary*) rawArgs; + + NSArray* x = (NSArray*) args[@"x"]; + NSArray* y = (NSArray*) args[@"y"]; + + NSMutableArray* result = [NSMutableArray arrayWithCapacity:x.count]; + + for (NSUInteger i = 0; i < x.count; i++) { + CGPoint cgPoint = CGPointMake([x[i] floatValue], [y[i] floatValue]); + NSValue *valuePoint = [NSValue valueWithCGPoint:cgPoint]; + + [result addObject:valuePoint]; + } + + methodResult(result); + } else { + methodResult(FlutterMethodNotImplemented); + } +} diff --git a/ios/Classes/CGRectHandler.h b/ios/Classes/CGRectHandler.h new file mode 100644 index 0000000..3fed4eb --- /dev/null +++ b/ios/Classes/CGRectHandler.h @@ -0,0 +1,15 @@ +// +// CGRectHandler.h +// foundation_fluttify +// +// Created by Yohom Bao on 2020/4/20. +// + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +void CGRectHandler(NSString* method, id args, FlutterResult methodResult); + +NS_ASSUME_NONNULL_END diff --git a/ios/Classes/CGRectHandler.m b/ios/Classes/CGRectHandler.m new file mode 100644 index 0000000..b2b7b0c --- /dev/null +++ b/ios/Classes/CGRectHandler.m @@ -0,0 +1,78 @@ +// +// CGRectHandler.m +// foundation_fluttify +// +// Created by Yohom Bao on 2020/4/20. +// + +#import "CGRectHandler.h" + +extern BOOL enableLog; + +void CGRectHandler(NSString* method, id rawArgs, FlutterResult methodResult) { + if ([@"CGRect::create" isEqualToString:method]) { + NSDictionary* args = (NSDictionary*) rawArgs; + + CGFloat x = [(NSNumber*) args[@"x"] floatValue]; + CGFloat y = [(NSNumber*) args[@"y"] floatValue]; + CGFloat width = [(NSNumber*) args[@"width"] floatValue]; + CGFloat height = [(NSNumber*) args[@"height"] floatValue]; + + CGRect rect = CGRectMake(x, y, width, height); + + NSValue* result = [NSValue valueWithCGRect:rect]; + + methodResult(result); + } else if ([@"CGRect::getX" isEqualToString:method]) { + NSDictionary* args = (NSDictionary*) rawArgs; + + NSValue *value = (NSValue *) args[@"__this__"]; + if (value != nil && (NSNull*) value != [NSNull null]) { + CGRect cgRect = value.CGRectValue; + methodResult(@(cgRect.origin.x)); + } else { + methodResult([FlutterError errorWithCode:@"目标对象为nul" + message:@"目标对象为nul" + details:@"目标对象为nul"]); + } + } else if ([@"CGRect::getY" isEqualToString:method]) { + NSDictionary* args = (NSDictionary*) rawArgs; + + NSValue *value = (NSValue *) args[@"__this__"]; + if (value != nil && (NSNull*) value != [NSNull null]) { + CGRect cgRect = value.CGRectValue; + methodResult(@(cgRect.origin.y)); + } else { + methodResult([FlutterError errorWithCode:@"目标对象为nul" + message:@"目标对象为nul" + details:@"目标对象为nul"]); + } + } else if ([@"CGRect::getWidth" isEqualToString:method]) { + NSDictionary* args = (NSDictionary*) rawArgs; + + NSValue *value = (NSValue *) args[@"__this__"]; + if (value != nil && (NSNull*) value != [NSNull null]) { + CGRect cgRect = value.CGRectValue; + methodResult(@(cgRect.size.width)); + } else { + methodResult([FlutterError errorWithCode:@"目标对象为nul" + message:@"目标对象为nul" + details:@"目标对象为nul"]); + } + } else if ([@"CGRect::getHeight" isEqualToString:method]) { + NSDictionary* args = (NSDictionary*) rawArgs; + + NSValue *value = (NSValue *) args[@"__this__"]; + if (value != nil && (NSNull*) value != [NSNull null]) { + CGRect cgRect = value.CGRectValue; + methodResult(@(cgRect.size.height)); + } else { + methodResult([FlutterError errorWithCode:@"目标对象为nul" + message:@"目标对象为nul" + details:@"目标对象为nul"]); + } + } else { + methodResult(FlutterMethodNotImplemented); + } +} + diff --git a/ios/Classes/CGSizeHandler.h b/ios/Classes/CGSizeHandler.h new file mode 100644 index 0000000..cc6203f --- /dev/null +++ b/ios/Classes/CGSizeHandler.h @@ -0,0 +1,15 @@ +// +// CGSizeHandler.h +// foundation_fluttify +// +// Created by Yohom Bao on 2020/6/22. +// + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +void CGSizeHandler(NSString* method, id args, FlutterResult methodResult); + +NS_ASSUME_NONNULL_END diff --git a/ios/Classes/CGSizeHandler.m b/ios/Classes/CGSizeHandler.m new file mode 100644 index 0000000..3709a39 --- /dev/null +++ b/ios/Classes/CGSizeHandler.m @@ -0,0 +1,52 @@ +// +// CGSizeHandler.m +// foundation_fluttify +// +// Created by Yohom Bao on 2020/6/22. +// + +#import "CGSizeHandler.h" + +extern BOOL enableLog; + +void CGSizeHandler(NSString* method, id rawArgs, FlutterResult methodResult) { + if ([@"CGSize::create" isEqualToString:method]) { + NSDictionary* args = (NSDictionary*) rawArgs; + + CGFloat width = [(NSNumber*) args[@"width"] floatValue]; + CGFloat height = [(NSNumber*) args[@"height"] floatValue]; + + CGSize rect = CGSizeMake(width, height); + + NSValue* result = [NSValue valueWithCGSize:rect]; + + methodResult(result); + } else if ([@"CGSize::getWidth" isEqualToString:method]) { + NSDictionary* args = (NSDictionary*) rawArgs; + + NSValue *__this__ = (NSValue *) args[@"__this__"]; + if (__this__ != nil && (NSNull*) __this__ != [NSNull null]) { + CGSize cgSize = __this__.CGSizeValue; + methodResult(@(cgSize.width)); + } else { + methodResult([FlutterError errorWithCode:@"目标对象为nul" + message:@"目标对象为nul" + details:@"目标对象为nul"]); + } + } else if ([@"CGSize::getHeight" isEqualToString:method]) { + NSDictionary* args = (NSDictionary*) rawArgs; + + NSValue *__this__ = (NSValue *) args[@"__this__"]; + if (__this__ != nil && (NSNull*) __this__ != [NSNull null]) { + CGSize cgSize = __this__.CGSizeValue; + methodResult(@(cgSize.height)); + } else { + methodResult([FlutterError errorWithCode:@"目标对象为nul" + message:@"目标对象为nul" + details:@"目标对象为nul"]); + } + } else { + methodResult(FlutterMethodNotImplemented); + } +} + diff --git a/ios/Classes/FluttifyMessageCodec.h b/ios/Classes/FluttifyMessageCodec.h new file mode 100644 index 0000000..e40d88f --- /dev/null +++ b/ios/Classes/FluttifyMessageCodec.h @@ -0,0 +1,24 @@ +// +// FluttifyMessageCodec.h +// FMDB +// +// Created by Yohom Bao on 2020/8/31. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface FluttifyReaderWriter : FlutterStandardReaderWriter + +@end + +@interface FluttifyWriter : FlutterStandardWriter + +@end + +@interface FluttifyReader : FlutterStandardReader + +@end + +NS_ASSUME_NONNULL_END diff --git a/ios/Classes/FluttifyMessageCodec.m b/ios/Classes/FluttifyMessageCodec.m new file mode 100644 index 0000000..9a85766 --- /dev/null +++ b/ios/Classes/FluttifyMessageCodec.m @@ -0,0 +1,230 @@ +// +// FluttifyMessageCodec.m +// FMDB +// +// Created by Yohom Bao on 2020/8/31. +// + +#import "FluttifyMessageCodec.h" + +extern NSMutableDictionary *HEAP; + +typedef NS_ENUM(NSInteger, FluttifyField) { + FluttifyFieldNil, + FluttifyFieldTrue, + FluttifyFieldFalse, + FluttifyFieldInt32, + FluttifyFieldInt64, + FluttifyFieldIntHex, + FluttifyFieldFloat64, + FluttifyFieldString, + // The following must match the corresponding order from `FlutterStandardDataType`. + FluttifyFieldUInt8Data, + FluttifyFieldInt32Data, + FluttifyFieldInt64Data, + FluttifyFieldFloat64Data, + FluttifyFieldList, + FluttifyFieldMap, + FluttifyFieldEnum = 126, + FluttifyFieldRef = 127, +}; + +UInt8 elementSizeForFlutterStandardDataType(FlutterStandardDataType type) { + switch (type) { + case FlutterStandardDataTypeUInt8: + return 1; + case FlutterStandardDataTypeInt32: + return 4; + case FlutterStandardDataTypeInt64: + return 8; + case FlutterStandardDataTypeFloat64: + return 8; + default: + return 0; + } +} + +@implementation FluttifyReaderWriter +- (FlutterStandardWriter *)writerWithData:(NSMutableData *)data { + return [[FluttifyWriter alloc] initWithData:data]; +} + +- (FlutterStandardReader *)readerWithData:(NSData *)data { + return [[FluttifyReader alloc] initWithData:data]; +} +@end + +@implementation FluttifyWriter + +- (void)writeValue:(id)value { + if (value == nil || value == [NSNull null]) { + [self writeByte:FluttifyFieldNil]; + } else if ([value isKindOfClass:[NSNumber class]]) { + CFNumberRef number = (__bridge CFNumberRef) value; + BOOL success = NO; + if (CFGetTypeID(number) == CFBooleanGetTypeID()) { + BOOL b = CFBooleanGetValue((CFBooleanRef) number); + [self writeByte:(b ? FluttifyFieldTrue : FluttifyFieldFalse)]; + success = YES; + } else if (CFNumberIsFloatType(number)) { + Float64 f; + success = CFNumberGetValue(number, kCFNumberFloat64Type, &f); + if (success) { + [self writeByte:FluttifyFieldFloat64]; + [self writeAlignment:8]; + [self writeBytes:(UInt8 *) &f length:8]; + } + } else if (CFNumberGetByteSize(number) <= 4) { + SInt32 n; + success = CFNumberGetValue(number, kCFNumberSInt32Type, &n); + if (success) { + [self writeByte:FluttifyFieldInt32]; + [self writeBytes:(UInt8 *) &n length:4]; + } + } else if (CFNumberGetByteSize(number) <= 8) { + SInt64 n; + success = CFNumberGetValue(number, kCFNumberSInt64Type, &n); + if (success) { + [self writeByte:FluttifyFieldInt64]; + [self writeBytes:(UInt8 *) &n length:8]; + } + } + if (!success) { + NSLog(@"Unsupported value: %@ of number type %d", value, CFNumberGetType(number)); + NSAssert(NO, @"Unsupported value for standard codec"); + } + } else if ([value isKindOfClass:[NSString class]]) { + NSString *string = value; + [self writeByte:FluttifyFieldString]; + [self writeUTF8:string]; + } else if ([value isKindOfClass:[FlutterStandardTypedData class]]) { + FlutterStandardTypedData *typedData = value; + [self writeByte:(FluttifyField) (typedData.type + FluttifyFieldUInt8Data)]; + [self writeSize:typedData.elementCount]; + [self writeAlignment:typedData.elementSize]; + [self writeData:typedData.data]; + } + // 官方给NSData也自动转换了, 但是fluttify需要的是NSData对象, 所以这里去掉NSData的自动转换 + /*else if ([value isKindOfClass:[NSData class]]) { + [self writeValue:[FlutterStandardTypedData typedDataWithBytes:value]]; + } */ + else if ([value isKindOfClass:[NSArray class]]) { + NSArray *array = value; + [self writeByte:FluttifyFieldList]; + [self writeSize:array.count]; + for (id object in array) { + [self writeValue:object]; + } + } else if ([value isKindOfClass:[NSDictionary class]]) { + NSDictionary *dict = value; + [self writeByte:FluttifyFieldMap]; + [self writeSize:dict.count]; + for (id key in dict) { + [self writeValue:key]; + [self writeValue:dict[key]]; + } + } + // 传递NSObject类型 + else if ([value isKindOfClass:[NSObject class]]) { + NSUInteger hash = [value hash]; + NSString* refId = [NSString stringWithFormat:@"%@:%@", NSStringFromClass([value class]), @(hash)]; + [self writeByte:FluttifyFieldRef]; + [self writeUTF8:refId]; + HEAP[refId] = value; + } else { + NSLog(@"Unsupported value: %@ of type %@", value, [value class]); + NSAssert(NO, @"Unsupported value for standard codec"); + } +} +@end + +@implementation FluttifyReader + +- (FlutterStandardTypedData *)readTypedDataOfType:(FlutterStandardDataType)type { + UInt32 elementCount = [self readSize]; + UInt8 elementSize = elementSizeForFlutterStandardDataType(type); + [self readAlignment:elementSize]; + NSData *data = [self readData:elementCount * elementSize]; + + switch (type) { + case FlutterStandardDataTypeUInt8: + return [FlutterStandardTypedData typedDataWithBytes:data]; + case FlutterStandardDataTypeInt32: + return [FlutterStandardTypedData typedDataWithInt32:data]; + case FlutterStandardDataTypeInt64: + return [FlutterStandardTypedData typedDataWithInt64:data]; + case FlutterStandardDataTypeFloat64: + return [FlutterStandardTypedData typedDataWithFloat64:data]; + default: + return nil; + } +} + +- (nullable id)readValueOfType:(UInt8)type { + FluttifyField field = (FluttifyField) type; + switch (field) { + case FluttifyFieldNil: + return nil; + case FluttifyFieldTrue: + return @YES; + case FluttifyFieldFalse: + return @NO; + case FluttifyFieldInt32: { + SInt32 value; + [self readBytes:&value length:4]; + return @(value); + } + case FluttifyFieldInt64: { + SInt64 value; + [self readBytes:&value length:8]; + return @(value); + } + case FluttifyFieldFloat64: { + Float64 value; + [self readAlignment:8]; + [self readBytes:&value length:8]; + return @(value); + } + case FluttifyFieldIntHex: + case FluttifyFieldString: + return [self readUTF8]; + case FluttifyFieldUInt8Data: + case FluttifyFieldInt32Data: + case FluttifyFieldInt64Data: + case FluttifyFieldFloat64Data: + return [self readTypedDataOfType:(FlutterStandardDataType) (field - FluttifyFieldUInt8Data)]; + case FluttifyFieldList: { + UInt32 length = [self readSize]; + NSMutableArray *array = [NSMutableArray arrayWithCapacity:length]; + for (UInt32 i = 0; i < length; i++) { + id value = [self readValue]; + [array addObject:(value == nil ? [NSNull null] : value)]; + } + return array; + } + case FluttifyFieldMap: { + UInt32 size = [self readSize]; + NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:size]; + for (UInt32 i = 0; i < size; i++) { + id key = [self readValue]; + id val = [self readValue]; + dict[key == nil ? [NSNull null] : key] = val == nil ? [NSNull null] : val; + } + return dict; + } + // 枚举类型直接使用int值 + case FluttifyFieldEnum: { + SInt32 value; + [self readBytes:&value length:4]; + return @(value); + } + case FluttifyFieldRef: { + NSString *refId = [self readUTF8]; + return HEAP[refId]; + } + default: + NSAssert(NO, @"Corrupted standard message"); + return nil; + } +} +@end diff --git a/ios/Classes/FoundationFluttifyPlugin.h b/ios/Classes/FoundationFluttifyPlugin.h new file mode 100644 index 0000000..f0095c5 --- /dev/null +++ b/ios/Classes/FoundationFluttifyPlugin.h @@ -0,0 +1,9 @@ +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface FoundationFluttifyPlugin : NSObject +- (instancetype) initWithRegistrar:(NSObject*) registrar; +@end + +NS_ASSUME_NONNULL_END diff --git a/ios/Classes/FoundationFluttifyPlugin.m b/ios/Classes/FoundationFluttifyPlugin.m new file mode 100644 index 0000000..5676ae1 --- /dev/null +++ b/ios/Classes/FoundationFluttifyPlugin.m @@ -0,0 +1,410 @@ +#import "FoundationFluttifyPlugin.h" +#import "PlatformService.h" +#import "UIImageHandler.h" +#import "UIViewHandler.h" +#import "CGPointHandler.h" +#import "NSDataHandler.h" +#import "NSDateHandler.h" +#import "UIEdgeInsetsHandler.h" +#import "UIColorHandler.h" +#import "NSErrorHandler.h" +#import "CGRectHandler.h" +#import "CGSizeHandler.h" +#import "UIViewControllerHandler.h" +#import "UIImageViewHandler.h" +#import "NSObjectHandler.h" +#import "platform_view/UIViewFactory.h" +#import "FluttifyMessageCodec.h" + +// The stack that exists on the Dart side for a method call is enabled only when the MethodChannel passing parameters are limited +NSMutableDictionary *STACK; + +// Container for Dart side random access objects +NSMutableDictionary *HEAP; + +// whether enable log or not +BOOL enableLog; + +NSString *_channelName = @"com.fluttify/foundation_method"; + +@implementation FoundationFluttifyPlugin { + NSObject *_registrar; +} + ++ (void)registerWithRegistrar:(NSObject *)registrar { + // 栈容器 + STACK = @{}.mutableCopy; + // 堆容器 + HEAP = @{}.mutableCopy; + + FlutterMethodChannel *channel = [FlutterMethodChannel + methodChannelWithName:_channelName + binaryMessenger:[registrar messenger] + codec:[FlutterStandardMethodCodec codecWithReaderWriter:[[FluttifyReaderWriter alloc] init]]]; + + FoundationFluttifyPlugin *instance = [[FoundationFluttifyPlugin alloc] initWithRegistrar:registrar]; + [registrar addMethodCallDelegate:instance channel:channel]; + [registrar registerViewFactory:[[UIViewFactory alloc] initWithRegistrar:registrar] withId:@"me.yohom/foundation_fluttify/UIView"]; +} + +- (instancetype)initWithRegistrar:(NSObject *)registrar { + self = [super init]; + if (self) { + _registrar = registrar; + [_registrar addApplicationDelegate:self]; + } + return self; +} + +- (void)handleMethodCall:(FlutterMethodCall *)methodCall result:(FlutterResult)methodResult { + id rawArgs = [methodCall arguments]; + if ([methodCall.method hasPrefix:@"UIImage::"]) { + UIImageHandler(methodCall.method, rawArgs, methodResult); + } else if ([methodCall.method hasPrefix:@"UIViewController::"]) { + UIViewControllerHandler(methodCall.method, rawArgs, methodResult); + } else if ([methodCall.method hasPrefix:@"UIView::"]) { + UIViewHandler(methodCall.method, rawArgs, methodResult); + } else if ([methodCall.method hasPrefix:@"CGPoint::"]) { + CGPointHandler(methodCall.method, rawArgs, methodResult); + } else if ([methodCall.method hasPrefix:@"NSData::"]) { + NSDataHandler(methodCall.method, rawArgs, methodResult); + } else if ([methodCall.method hasPrefix:@"UIEdgeInsets::"]) { + UIEdgeInsetsHandler(methodCall.method, rawArgs, methodResult); + } else if ([methodCall.method hasPrefix:@"UIColor::"]) { + UIColorHandler(methodCall.method, rawArgs, methodResult); + } else if ([methodCall.method hasPrefix:@"NSError::"]) { + NSErrorHandler(methodCall.method, rawArgs, methodResult); + } else if ([methodCall.method hasPrefix:@"CGRect::"]) { + CGRectHandler(methodCall.method, rawArgs, methodResult); + } else if ([methodCall.method hasPrefix:@"CGSize::"]) { + CGSizeHandler(methodCall.method, rawArgs, methodResult); + } else if ([methodCall.method hasPrefix:@"UIImageView::"]) { + UIImageViewHandler(methodCall.method, rawArgs, methodResult); + } else if ([methodCall.method hasPrefix:@"NSObject::"]) { + NSObjectHandler(methodCall.method, rawArgs, methodResult); + } else if ([methodCall.method hasPrefix:@"NSDate::"]) { + NSDateHandler(methodCall.method, rawArgs, methodResult); + } else if ([methodCall.method hasPrefix:@"Platform"]) { + PlatformService(methodCall.method, rawArgs, methodResult, self->_registrar); + } else { + methodResult(FlutterMethodNotImplemented); + } +} + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + if (enableLog) { + NSLog(@"application:didFinishLaunchingWithOptions"); + } + FlutterMethodChannel *channel = [FlutterMethodChannel + methodChannelWithName:_channelName + binaryMessenger:[_registrar messenger] + codec:[FlutterStandardMethodCodec codecWithReaderWriter:[[FluttifyReaderWriter alloc] init]]]; + + [channel invokeMethod:@"applicationDidFinishLaunchingWithOptions" + arguments:@{@"application": application, @"launchOptions": @{}}]; // 由于无法预知NSDictionary里的类型, 这里不传输了 + return YES; +} + +/** + * Called if this has been registered for `UIApplicationDelegate` callbacks. + * + * @return `NO` if this vetoes application launch. + */ +- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + if (enableLog) { + NSLog(@"application:willFinishLaunchingWithOptions"); + } + FlutterMethodChannel *channel = [FlutterMethodChannel + methodChannelWithName:_channelName + binaryMessenger:[_registrar messenger] + codec:[FlutterStandardMethodCodec codecWithReaderWriter:[[FluttifyReaderWriter alloc] init]]]; + + [channel invokeMethod:@"applicationWillFinishLaunchingWithOptions" + arguments:@{@"application": application, @"launchOptions": @{}}]; + return YES; +} + +/** + * Called if this has been registered for `UIApplicationDelegate` callbacks. + */ +- (void)applicationDidBecomeActive:(UIApplication *)application { + if (enableLog) { + NSLog(@"applicationDidBecomeActive"); + } + FlutterMethodChannel *channel = [FlutterMethodChannel + methodChannelWithName:_channelName + binaryMessenger:[_registrar messenger] + codec:[FlutterStandardMethodCodec codecWithReaderWriter:[[FluttifyReaderWriter alloc] init]]]; + + [channel invokeMethod:@"applicationDidBecomeActive" + arguments:@{@"application": application}]; +} + +/** + * Called if this has been registered for `UIApplicationDelegate` callbacks. + */ +- (void)applicationWillResignActive:(UIApplication *)application { + if (enableLog) { + NSLog(@"applicationWillResignActive"); + } + FlutterMethodChannel *channel = [FlutterMethodChannel + methodChannelWithName:_channelName + binaryMessenger:[_registrar messenger] + codec:[FlutterStandardMethodCodec codecWithReaderWriter:[[FluttifyReaderWriter alloc] init]]]; + + [channel invokeMethod:@"applicationWillResignActive" + arguments:@{@"application": application}]; +} + +/** + * Called if this has been registered for `UIApplicationDelegate` callbacks. + */ +- (void)applicationDidEnterBackground:(UIApplication *)application { + if (enableLog) { + NSLog(@"applicationDidEnterBackground"); + } + FlutterMethodChannel *channel = [FlutterMethodChannel + methodChannelWithName:_channelName + binaryMessenger:[_registrar messenger] + codec:[FlutterStandardMethodCodec codecWithReaderWriter:[[FluttifyReaderWriter alloc] init]]]; + + [channel invokeMethod:@"applicationDidEnterBackground" + arguments:@{@"application": application}]; +} + +/** + * Called if this has been registered for `UIApplicationDelegate` callbacks. + */ +- (void)applicationWillEnterForeground:(UIApplication *)application { + if (enableLog) { + NSLog(@"applicationWillEnterForeground"); + } + FlutterMethodChannel *channel = [FlutterMethodChannel + methodChannelWithName:_channelName + binaryMessenger:[_registrar messenger] + codec:[FlutterStandardMethodCodec codecWithReaderWriter:[[FluttifyReaderWriter alloc] init]]]; + + [channel invokeMethod:@"applicationWillEnterForeground" + arguments:@{@"application": application}]; +} + +/** + Called if this has been registered for `UIApplicationDelegate` callbacks. + */ +- (void)applicationWillTerminate:(UIApplication *)application { + if (enableLog) { + NSLog(@"applicationWillTerminate"); + } + FlutterMethodChannel *channel = [FlutterMethodChannel + methodChannelWithName:_channelName + binaryMessenger:[_registrar messenger] + codec:[FlutterStandardMethodCodec codecWithReaderWriter:[[FluttifyReaderWriter alloc] init]]]; + + [channel invokeMethod:@"applicationWillTerminate" + arguments:@{@"application": application}]; +} + +/** + * Called if this has been registered for `UIApplicationDelegate` callbacks. + */ +- (void) application:(UIApplication *)application +didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings +API_DEPRECATED( + "See -[UIApplicationDelegate application:didRegisterUserNotificationSettings:] deprecation", + ios(8.0, 10.0)) { + if (enableLog) { + NSLog(@"application:didRegisterUserNotificationSettings"); + } + FlutterMethodChannel *channel = [FlutterMethodChannel + methodChannelWithName:_channelName + binaryMessenger:[_registrar messenger] + codec:[FlutterStandardMethodCodec codecWithReaderWriter:[[FluttifyReaderWriter alloc] init]]]; + + [channel invokeMethod:@"applicationDidRegisterUserNotificationSettings" + arguments:@{@"application": application, @"notificationSettings": notificationSettings}]; +} + +/** + * Called if this has been registered for `UIApplicationDelegate` callbacks. + */ +- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { + if (enableLog) { + NSLog(@"application:didRegisterForRemoteNotificationsWithDeviceToken"); + } + FlutterMethodChannel *channel = [FlutterMethodChannel + methodChannelWithName:_channelName + binaryMessenger:[_registrar messenger] + codec:[FlutterStandardMethodCodec codecWithReaderWriter:[[FluttifyReaderWriter alloc] init]]]; + + [channel invokeMethod:@"applicationDidRegisterForRemoteNotificationsWithDeviceToken" + arguments:@{@"application": application, @"deviceToken": deviceToken}]; +} + +/** + * Called if this has been registered for `UIApplicationDelegate` callbacks. + * + * @return `YES` if this handles the request. + */ +- (BOOL) application:(UIApplication *)application +didReceiveRemoteNotification:(NSDictionary *)userInfo + fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler { + if (enableLog) { + NSLog(@"application:didReceiveRemoteNotification:fetchCompletionHandler"); + } + FlutterMethodChannel *channel = [FlutterMethodChannel + methodChannelWithName:_channelName + binaryMessenger:[_registrar messenger] + codec:[FlutterStandardMethodCodec codecWithReaderWriter:[[FluttifyReaderWriter alloc] init]]]; + + [channel invokeMethod:@"applicationDidReceiveRemoteNotificationFetchCompletionHandler" + arguments:@{@"application": application, @"userInfo": userInfo}]; + return NO; +} + +/** + * Called if this has been registered for `UIApplicationDelegate` callbacks. + * + * @return `YES` if this handles the request. + */ +- (BOOL)application:(UIApplication *)application + openURL:(NSURL *)url + options:(NSDictionary *)options { + if (enableLog) { + NSLog(@"application:openURL:options"); + } + FlutterMethodChannel *channel = [FlutterMethodChannel + methodChannelWithName:_channelName + binaryMessenger:[_registrar messenger] + codec:[FlutterStandardMethodCodec codecWithReaderWriter:[[FluttifyReaderWriter alloc] init]]]; + + [channel invokeMethod:@"applicationOpenURLOptions" + arguments:@{@"application": application, @"url": url, @"options": @{}}]; + return NO; +} + +/** + * Called if this has been registered for `UIApplicationDelegate` callbacks. + * + * @return `YES` if this handles the request. + */ +- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url { + if (enableLog) { + NSLog(@"application:handleOpenURL"); + } + FlutterMethodChannel *channel = [FlutterMethodChannel + methodChannelWithName:_channelName + binaryMessenger:[_registrar messenger] + codec:[FlutterStandardMethodCodec codecWithReaderWriter:[[FluttifyReaderWriter alloc] init]]]; + + [channel invokeMethod:@"applicationHandleOpenURL" + arguments:@{@"application": application, @"url": url}]; + return NO; +} + +/** + * Called if this has been registered for `UIApplicationDelegate` callbacks. + * + * @return `YES` if this handles the request. + */ +- (BOOL)application:(UIApplication *)application + openURL:(NSURL *)url + sourceApplication:(NSString *)sourceApplication + annotation:(id)annotation { + if (enableLog) { + NSLog(@"application:openURL:sourceApplication:annotation"); + } + FlutterMethodChannel *channel = [FlutterMethodChannel + methodChannelWithName:_channelName + binaryMessenger:[_registrar messenger] + codec:[FlutterStandardMethodCodec codecWithReaderWriter:[[FluttifyReaderWriter alloc] init]]]; + + [channel invokeMethod:@"applicationOpenURLSourceApplicationAnnotation" + arguments:@{@"application": application, @"url": url, @"sourceApplication": sourceApplication, @"annotation": (NSObject *) annotation}]; + return NO; +} + +/** + * Called if this has been registered for `UIApplicationDelegate` callbacks. + * + * @return `YES` if this handles the request. + */ +- (BOOL) application:(UIApplication *)application +performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem + completionHandler:(void (^)(BOOL succeeded))completionHandler +API_AVAILABLE(ios(9.0)) { + if (enableLog) { + NSLog(@"application:performActionForShortcutItem:completionHandler"); + } + FlutterMethodChannel *channel = [FlutterMethodChannel + methodChannelWithName:_channelName + binaryMessenger:[_registrar messenger] + codec:[FlutterStandardMethodCodec codecWithReaderWriter:[[FluttifyReaderWriter alloc] init]]]; + + [channel invokeMethod:@"applicationPerformActionForShortcutItemCompletionHandler" + arguments:@{@"application": application, @"shortcutItem": shortcutItem}]; + return NO; +} + +/** + * Called if this has been registered for `UIApplicationDelegate` callbacks. + * + * @return `YES` if this handles the request. + */ +- (BOOL) application:(UIApplication *)application +handleEventsForBackgroundURLSession:(nonnull NSString *)identifier + completionHandler:(nonnull void (^)(void))completionHandler { + if (enableLog) { + NSLog(@"application:handleEventsForBackgroundURLSession:completionHandler"); + } + FlutterMethodChannel *channel = [FlutterMethodChannel + methodChannelWithName:_channelName + binaryMessenger:[_registrar messenger] + codec:[FlutterStandardMethodCodec codecWithReaderWriter:[[FluttifyReaderWriter alloc] init]]]; + + [channel invokeMethod:@"applicationHandleEventsForBackgroundURLSessionCompletionHandler" + arguments:@{@"application": application, @"identifier": identifier}]; + return NO; +} + +/** + * Called if this has been registered for `UIApplicationDelegate` callbacks. + * + * @return `YES` if this handles the request. + */ +- (BOOL) application:(UIApplication *)application +performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler { + if (enableLog) { + NSLog(@"application:performFetchWithCompletionHandler"); + } + FlutterMethodChannel *channel = [FlutterMethodChannel + methodChannelWithName:_channelName + binaryMessenger:[_registrar messenger] + codec:[FlutterStandardMethodCodec codecWithReaderWriter:[[FluttifyReaderWriter alloc] init]]]; + + [channel invokeMethod:@"applicationPerformFetchWithCompletionHandler" + arguments:@{@"application": application}]; + return NO; +} + +/** + * Called if this has been registered for `UIApplicationDelegate` callbacks. + * + * @return `YES` if this handles the request. + */ +- (BOOL) application:(UIApplication *)application +continueUserActivity:(NSUserActivity *)userActivity + restorationHandler:(void (^)(NSArray *))restorationHandler { + if (enableLog) { + NSLog(@"application:continueUserActivity:restorationHandler"); + } + FlutterMethodChannel *channel = [FlutterMethodChannel + methodChannelWithName:_channelName + binaryMessenger:[_registrar messenger] + codec:[FlutterStandardMethodCodec codecWithReaderWriter:[[FluttifyReaderWriter alloc] init]]]; + + [channel invokeMethod:@"applicationContinueUserActivityRestorationHandler" + arguments:@{@"application": application, @"userActivity": userActivity}]; + return NO; +} + +@end diff --git a/ios/Classes/NSDataHandler.h b/ios/Classes/NSDataHandler.h new file mode 100644 index 0000000..23683f4 --- /dev/null +++ b/ios/Classes/NSDataHandler.h @@ -0,0 +1,12 @@ +// +// Created by Yohom Bao on 2019/11/25. +// + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +void NSDataHandler(NSString* method, id args, FlutterResult methodResult); + +NS_ASSUME_NONNULL_END diff --git a/ios/Classes/NSDataHandler.m b/ios/Classes/NSDataHandler.m new file mode 100644 index 0000000..8cfa3c3 --- /dev/null +++ b/ios/Classes/NSDataHandler.m @@ -0,0 +1,36 @@ +// +// Created by Yohom Bao on 2019/11/25. +// + +#import "NSDataHandler.h" + +extern BOOL enableLog; + +void NSDataHandler(NSString* method, id rawArgs, FlutterResult methodResult) { + if ([@"NSData::createWithUint8List" isEqualToString:method]) { + NSDictionary* args = (NSDictionary*) rawArgs; + + FlutterStandardTypedData *data = (FlutterStandardTypedData *) args[@"data"]; + if (data != nil && (NSNull*) data != [NSNull null]) { + NSData *target = data.data; + methodResult(target); + } else { + methodResult([FlutterError errorWithCode:@"目标对象为nul" + message:@"目标对象为nul" + details:@"目标对象为nul"]); + } + } else if ([@"NSData::getData" isEqualToString:method]) { + NSDictionary* args = (NSDictionary*) rawArgs; + + NSData *target = (NSData *) args[@"__this__"]; + if (target != nil && (NSNull*) target != [NSNull null]) { + methodResult([FlutterStandardTypedData typedDataWithBytes:target]); + } else { + methodResult([FlutterError errorWithCode:@"目标对象为nul" + message:@"目标对象为nul" + details:@"目标对象为nul"]); + } + } else { + methodResult(FlutterMethodNotImplemented); + } +} diff --git a/ios/Classes/NSDateHandler.h b/ios/Classes/NSDateHandler.h new file mode 100644 index 0000000..fedcad7 --- /dev/null +++ b/ios/Classes/NSDateHandler.h @@ -0,0 +1,15 @@ +// +// NSDateHandler.h +// foundation_fluttify +// +// Created by Yohom Bao on 2020/11/9. +// + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +void NSDateHandler(NSString* method, id args, FlutterResult methodResult); + +NS_ASSUME_NONNULL_END diff --git a/ios/Classes/NSDateHandler.m b/ios/Classes/NSDateHandler.m new file mode 100644 index 0000000..072838c --- /dev/null +++ b/ios/Classes/NSDateHandler.m @@ -0,0 +1,27 @@ +// +// NSDateHandler.m +// foundation_fluttify +// +// Created by Yohom Bao on 2020/11/9. +// + +#import "NSDateHandler.h" + +extern BOOL enableLog; + +void NSDateHandler(NSString* method, id rawArgs, FlutterResult methodResult) { + if ([@"NSDate::get_timeIntervalSince1970" isEqualToString:method]) { + NSDictionary* args = (NSDictionary*) rawArgs; + + NSDate *target = (NSDate *) args[@"__this__"]; + if (target != nil && (NSNull*) target != [NSNull null]) { + methodResult(@(target.timeIntervalSince1970)); + } else { + methodResult([FlutterError errorWithCode:@"目标对象为nul" + message:@"目标对象为nul" + details:@"目标对象为nul"]); + } + } else { + methodResult(FlutterMethodNotImplemented); + } +} diff --git a/ios/Classes/NSErrorHandler.h b/ios/Classes/NSErrorHandler.h new file mode 100644 index 0000000..eb6171b --- /dev/null +++ b/ios/Classes/NSErrorHandler.h @@ -0,0 +1,15 @@ +// +// NSErrorHandler.h +// foundation_fluttify +// +// Created by Yohom Bao on 2020/4/5. +// + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +void NSErrorHandler(NSString* method, id args, FlutterResult methodResult); + +NS_ASSUME_NONNULL_END diff --git a/ios/Classes/NSErrorHandler.m b/ios/Classes/NSErrorHandler.m new file mode 100644 index 0000000..56d6176 --- /dev/null +++ b/ios/Classes/NSErrorHandler.m @@ -0,0 +1,39 @@ +// +// NSErrorHandler.m +// foundation_fluttify +// +// Created by Yohom Bao on 2020/4/5. +// + +#import "NSErrorHandler.h" + +extern BOOL enableLog; + +void NSErrorHandler(NSString* method, id rawArgs, FlutterResult methodResult) { + if ([@"NSError::getCode" isEqualToString:method]) { + NSDictionary* args = (NSDictionary*) rawArgs; + + NSError *target = (NSError *) args[@"__this__"]; + if (target != nil && (NSNull*) target != [NSNull null]) { + methodResult(@(target.code)); + } else { + methodResult([FlutterError errorWithCode:@"目标对象为nul" + message:@"目标对象为nul" + details:@"目标对象为nul"]); + } + } else if ([@"NSError::getDescription" isEqualToString:method]) { + NSDictionary* args = (NSDictionary*) rawArgs; + + NSError *target = (NSError *) args[@"__this__"]; + if (target != nil && (NSNull*) target != [NSNull null]) { + methodResult(target.description); + } else { + methodResult([FlutterError errorWithCode:@"目标对象为nul" + message:@"目标对象为nul" + details:@"目标对象为nul"]); + } + } else { + methodResult(FlutterMethodNotImplemented); + } +} + diff --git a/ios/Classes/NSObjectHandler.h b/ios/Classes/NSObjectHandler.h new file mode 100644 index 0000000..ec0dcad --- /dev/null +++ b/ios/Classes/NSObjectHandler.h @@ -0,0 +1,15 @@ +// +// NSObjectHandler.h +// FMDB +// +// Created by Yohom Bao on 2020/9/14. +// + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +void NSObjectHandler(NSString* method, id args, FlutterResult methodResult); + +NS_ASSUME_NONNULL_END diff --git a/ios/Classes/NSObjectHandler.m b/ios/Classes/NSObjectHandler.m new file mode 100644 index 0000000..7cd37ed --- /dev/null +++ b/ios/Classes/NSObjectHandler.m @@ -0,0 +1,32 @@ +// +// NSObjectHandler.m +// FMDB +// +// Created by Yohom Bao on 2020/9/14. +// + +#import "NSObjectHandler.h" + +extern BOOL enableLog; + +void NSObjectHandler(NSString* method, id rawArgs, FlutterResult methodResult) { + if ([@"NSObject::init" isEqualToString:method]) { + NSDictionary* args = (NSDictionary*) rawArgs; + + NSObject *__this__ = (NSObject *) args[@"__this__"]; + + NSObject *target = [__this__ init]; + + methodResult(target); + } else if ([@"NSObject::init_batch" isEqualToString:method]) { + NSDictionary* args = (NSDictionary*) rawArgs; + + NSObject *__this__ = (NSObject *) args[@"__this__"]; + + NSObject *target = [__this__ init]; + + methodResult(target); + } else { + methodResult(FlutterMethodNotImplemented); + } +} diff --git a/ios/Classes/PlatformService.h b/ios/Classes/PlatformService.h new file mode 100644 index 0000000..8d45c0c --- /dev/null +++ b/ios/Classes/PlatformService.h @@ -0,0 +1,15 @@ +// +// PlatformFactoryHandler.h +// foundation_fluttify +// +// Created by Yohom Bao on 2019/11/22. +// + +#import "FoundationFluttifyPlugin.h" +#import + +NS_ASSUME_NONNULL_BEGIN + +void PlatformService(NSString* method, id args, FlutterResult methodResult, NSObject* registrar); + +NS_ASSUME_NONNULL_END diff --git a/ios/Classes/PlatformService.m b/ios/Classes/PlatformService.m new file mode 100644 index 0000000..23fd948 --- /dev/null +++ b/ios/Classes/PlatformService.m @@ -0,0 +1,352 @@ +// +// PlatformFactoryHandler.m +// foundation_fluttify +// +// Created by Yohom Bao on 2019/11/22. +// + +#import "PlatformService.h" +#import +#import + +extern NSMutableDictionary *STACK; +extern NSMutableDictionary *HEAP; +extern BOOL enableLog; + +void PlatformService(NSString* method, id rawArgs, FlutterResult methodResult, NSObject* registrar) { + // toggle log + if ([@"PlatformService::enableLog" isEqualToString:method]) { + NSDictionary* args = (NSDictionary*) rawArgs; + + enableLog = [args[@"enable"] boolValue]; + methodResult(@"success"); + } + // 通过反射调用方法 + else if ([@"PlatformService::performSelectorWithObject" isEqualToString:method]) { + NSDictionary* args = (NSDictionary*) rawArgs; + + NSString *selector = (NSString *) args[@"selector"]; + NSObject *object = (NSObject *) args[@"object"]; + + NSObject *__this__ = (NSObject *) args[@"__this__"]; + if (__this__ != nil && (NSNull*) __this__ != [NSNull null]) { + [__this__ performSelector:NSSelectorFromString(selector) withObject:object]; + methodResult(@"success"); + } else { + methodResult([FlutterError errorWithCode:@"目标对象为nul" + message:@"目标对象为nul" + details:@"目标对象为nul"]); + } + } + // 判断当前对象是否存在 + else if ([@"PlatformService::isNull" isEqualToString:method]) { + NSDictionary* args = (NSDictionary*) rawArgs; + + NSObject *__this__ = (NSObject *) args[@"__this__"]; + methodResult(@(__this__ == nil || (NSNull*) __this__ == [NSNull null])); + } + // 为对象添加字段 + else if ([@"PlatformService::addProperty" isEqualToString:method]) { + NSDictionary* args = (NSDictionary*) rawArgs; + + NSInteger propertyKey = [(NSNumber *) args[@"propertyKey"] integerValue]; + NSObject *property__ = (NSObject *) args[@"property"]; + + NSObject *__this__ = args[@"__this__"]; + + if (__this__ && (NSNull*) __this__ != [NSNull null]) { + objc_setAssociatedObject(__this__, (const void *) propertyKey, property__, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + methodResult(@"success"); + } else { + methodResult([FlutterError errorWithCode:@"目标对象为空" message:@"目标对象为空" details:@"目标对象为空"]); + } + } + // 为对象添加列表字段 + else if ([@"PlatformService::addListProperty" isEqualToString:method]) { + NSDictionary* args = (NSDictionary*) rawArgs; + + NSInteger propertyKey = [(NSNumber *) args[@"propertyKey"] integerValue]; + NSArray* property__ = (NSArray*) args[@"property"]; + + NSObject *__this__ = args[@"__this__"]; + + if (__this__ && (NSNull*) __this__ != [NSNull null]) { + objc_setAssociatedObject(__this__, (const void *) propertyKey, property__, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + methodResult(@"success"); + } else { + methodResult([FlutterError errorWithCode:@"目标对象为空" message:@"目标对象为空" details:@"目标对象为空"]); + } + } + // 批量为对象添加字段 + else if ([@"PlatformService::addProperty_batch" isEqualToString:method]) { + NSArray*>* argsBatch = (NSArray*>*) rawArgs; + + NSMutableArray* resultList = [NSMutableArray array]; + + for (NSUInteger __i__ = 0; __i__ < argsBatch.count; __i__++) { + NSDictionary* args = argsBatch[__i__]; + + NSInteger propertyKey = [(NSNumber *) args[@"propertyKey"] integerValue]; + NSObject *property__ = (NSObject *) args[@"property"]; + + NSObject *__this__ = args[@"__this__"]; + + if (__this__ && (NSNull*) __this__ != [NSNull null]) { + objc_setAssociatedObject(__this__, (const void *) propertyKey, property__, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + [resultList addObject:@"success"]; + } else { + methodResult([FlutterError errorWithCode:@"目标对象为空" message:@"目标对象为空" details:@"目标对象为空"]); + break; + } + } + + methodResult(resultList); + } + // 获取添加字段的值 + else if ([@"PlatformService::getProperty" isEqualToString:method]) { + NSDictionary* args = (NSDictionary*) rawArgs; + + NSInteger propertyKey = [(NSNumber *) args[@"propertyKey"] integerValue]; + + NSObject *__this__ = args[@"__this__"]; + + if (__this__ && (NSNull*) __this__ != [NSNull null]) { + NSObject *result = objc_getAssociatedObject(__this__, (const void *) propertyKey); + methodResult(result); + } else { + methodResult([FlutterError errorWithCode:@"目标对象为空" message:@"目标对象为空" details:@"目标对象为空"]); + } + } + // 批量获取添加字段的值 + else if ([@"PlatformService::getProperty_batch" isEqualToString:method]) { + NSArray*>* argsBatch = (NSArray*>*) rawArgs; + + NSMutableArray* resultList = [NSMutableArray array]; + + for (NSUInteger __i__ = 0; __i__ < argsBatch.count; __i__++) { + NSDictionary* args = argsBatch[__i__]; + + NSInteger propertyKey = [(NSNumber *) args[@"propertyKey"] integerValue]; + + NSObject *__this__ = args[@"__this__"]; + + if (__this__ && (NSNull*) __this__ != [NSNull null]) { + NSObject *result = objc_getAssociatedObject(__this__, (const void *) propertyKey); + [resultList addObject:result]; + } else { + methodResult([FlutterError errorWithCode:@"目标对象为空" message:@"目标对象为空" details:@"目标对象为空"]); + break; + } + } + + methodResult(resultList); + } + // 为对象添加jsonable字段 + else if ([@"PlatformService::addJsonableProperty" isEqualToString:method]) { + NSDictionary* args = (NSDictionary*) rawArgs; + + NSInteger propertyKey = [(NSNumber *) args[@"propertyKey"] integerValue]; + NSObject *property = (NSObject *) args[@"property"]; + + NSObject *__this__ = args[@"__this__"]; + + if (__this__ && (NSNull*) __this__ != [NSNull null]) { + objc_setAssociatedObject(__this__, (const void *) propertyKey, property, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + methodResult(@"success"); + } else { + methodResult([FlutterError errorWithCode:@"目标对象为空" message:@"目标对象为空" details:@"目标对象为空"]); + } + } + // 批量为对象添加jsonable字段 + else if ([@"PlatformService::addJsonableProperty_batch" isEqualToString:method]) { + NSArray*>* argsBatch = (NSArray*>*) rawArgs; + + NSMutableArray* resultList = [NSMutableArray array]; + + for (NSUInteger __i__ = 0; __i__ < argsBatch.count; __i__++) { + NSDictionary* args = argsBatch[__i__]; + + NSInteger propertyKey = [(NSNumber *) args[@"propertyKey"] integerValue]; + NSObject *property = (NSObject *) args[@"property"]; + + NSObject *__this__ = args[@"__this__"]; + + if (__this__ && (NSNull*) __this__ != [NSNull null]) { + objc_setAssociatedObject(__this__, (const void *) propertyKey, property, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + [resultList addObject:@"success"]; + } else { + methodResult([FlutterError errorWithCode:@"目标对象为空" message:@"目标对象为空" details:@"目标对象为空"]); + break; + } + } + + methodResult(resultList); + } + // 获取添加字段的jsonable值 + else if ([@"PlatformService::getJsonableProperty" isEqualToString:method]) { + NSDictionary* args = (NSDictionary*) rawArgs; + + NSInteger propertyKey = [(NSNumber *) args[@"propertyKey"] integerValue]; + + NSObject *__this__ = args[@"__this__"]; + + if (__this__ && (NSNull*) __this__ != [NSNull null]) { + methodResult(objc_getAssociatedObject(__this__, (const void *) propertyKey)); + } else { + methodResult([FlutterError errorWithCode:@"目标对象为空" message:@"目标对象为空" details:@"目标对象为空"]); + } + } + // 批量获取添加字段的jsonable值 + else if ([@"PlatformService::getJsonableProperty_batch" isEqualToString:method]) { + NSArray*>* argsBatch = (NSArray*>*) rawArgs; + + NSMutableArray* resultList = [NSMutableArray array]; + + for (NSUInteger __i__ = 0; __i__ < argsBatch.count; __i__++) { + NSDictionary* args = argsBatch[__i__]; + + NSInteger propertyKey = [(NSNumber *) args[@"propertyKey"] integerValue]; + + NSObject *__this__ = args[@"__this__"]; + + if (__this__ && (NSNull*) __this__ != [NSNull null]) { + NSObject* result = objc_getAssociatedObject(__this__, (const void *) propertyKey); + [resultList addObject:result]; + } else { + methodResult([FlutterError errorWithCode:@"目标对象为空" message:@"目标对象为空" details:@"目标对象为空"]); + break; + } + } + + methodResult(resultList); + } + // 释放一个对象 + else if ([@"PlatformService::release" isEqualToString:method]) { + NSDictionary* args = (NSDictionary*) rawArgs; + + NSNumber *__this__ = (NSNumber *) args[@"__this__"]; + + if (enableLog) NSLog(@"PlatformService::释放对象: %@", __this__); + + [HEAP removeObjectForKey:[NSString stringWithFormat:@"%@", __this__]]; + methodResult(@"success"); + + if (enableLog) NSLog(@"size: %ld, HEAP: %@", [HEAP count], HEAP); + } + // 释放一批对象 + else if ([@"PlatformService::release_batch" isEqualToString:method]) { + NSDictionary* args = (NSDictionary*) rawArgs; + + NSArray* __this_batch__ = (NSArray*) args[@"__this_batch__"]; + + if (enableLog) NSLog(@"PlatformService::批量释放对象: %@", __this_batch__); + + for (NSNumber* item in __this_batch__) { + [HEAP removeObjectForKey:[NSString stringWithFormat:@"%@", item]]; + } + methodResult(@"success"); + + if (enableLog) NSLog(@"size: %ld, HEAP: %@", [HEAP count], HEAP); + } + // 清空堆 + else if ([@"PlatformService::clearHeap" isEqualToString:method]) { + if (enableLog) NSLog(@"PlatformService::清空堆"); + + [HEAP removeAllObjects]; + methodResult(@"success"); + + if (enableLog) NSLog(@"size: %ld, HEAP: %@", [HEAP count], HEAP); + } + // 压入栈 + else if ([@"PlatformService::pushStack" isEqualToString:method]) { + NSDictionary* args = (NSDictionary*) rawArgs; + + NSString *name = (NSString *) args[@"name"]; + + NSObject *__this__ = (NSObject *) args[@"__this__"]; + + if (enableLog) NSLog(@"PlatformService::压入栈 %@@%@", NSStringFromClass([args[@"__this__"] class]), __this__); + + STACK[name] = __this__; + + methodResult(@"success"); + + if (enableLog) NSLog(@"STACK: %@", STACK); + } + // 压入栈 jsonable + else if ([@"PlatformService::pushStackJsonable" isEqualToString:method]) { + NSDictionary* args = (NSDictionary*) rawArgs; + + NSString *name = (NSString *) args[@"name"]; + NSObject *data = (NSObject *) args[@"data"]; + + if (enableLog) NSLog(@"PlatformService::压入栈 %@", data); + + STACK[name] = data; + + methodResult(@"success"); + + if (enableLog) NSLog(@"STACK: %@", STACK); + } + // 清空栈 + else if ([@"PlatformService::clearStack" isEqualToString:method]) { + if (enableLog) NSLog(@"PlatformService::清空栈"); + + [STACK removeAllObjects]; + methodResult(@"success"); + + if (enableLog) NSLog(@"STACK: %@", STACK); + } + // 打开一个ViewController + else if ([@"PlatformService::presentViewController" isEqualToString:method]) { + NSDictionary* args = (NSDictionary*) rawArgs; + + if (enableLog) NSLog(@"PlatformService::打开一个ViewController"); + NSString* viewControllerClass = (NSString*) args[@"viewControllerClass"]; + BOOL withNavigationController = [(NSNumber*) args[@"withNavigationController"] boolValue]; + + UIViewController *controller = (UIViewController *) [[NSClassFromString(viewControllerClass) alloc] init]; + if (withNavigationController) { + // UINavigationController *naviController = [[UINavigationController alloc] initWithRootViewController:controller]; + // UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithTitle:@"关闭" style:UIBarButtonItemStyleDone __this__:nil action:@selector(dismiss)]; + // [[controller navigationItem] setLeftBarButtonItem:item]; + // [[UIApplication sharedApplication].keyWindow.rootViewController presentViewController:naviController animated:YES completion:nil]; + } else { + [[UIApplication sharedApplication].keyWindow.rootViewController presentViewController:controller animated:YES completion:nil]; + } + methodResult(@"success"); + } + // 获取flutter asset的路径 + else if ([@"PlatformService::getAssetPath" isEqualToString:method]) { + NSDictionary* args = (NSDictionary*) rawArgs; + + NSString *flutterAssetPath = (NSString *) args[@"flutterAssetPath"]; + + if (enableLog) NSLog(@"PlatformService::Flutter Asset%@", flutterAssetPath); + + NSString* key = [registrar lookupKeyForAsset:flutterAssetPath]; + NSString* path = [[NSBundle mainBundle] pathForResource:key ofType:nil]; + + methodResult(path); + } + // viewId转refId + else if ([@"PlatformService::viewId2RefId" isEqualToString:method]) { + NSDictionary* args = (NSDictionary*) rawArgs; + + NSString *viewId = (NSString *) args[@"viewId"]; + + if (enableLog) NSLog(@"PlatformService::viewId%@", viewId); + + if ([[HEAP allKeys] containsObject:viewId]) { + NSObject* object = HEAP[viewId]; + methodResult([NSString stringWithFormat:@"%@", @(object.hash)]); + // 转换后删除viewId + [HEAP removeObjectForKey:viewId]; + } else { + methodResult([FlutterError errorWithCode:@"viewId无对应对象" message:@"viewId无对应对象" details:@"viewId无对应对象"]); + } + + } else { + methodResult(FlutterMethodNotImplemented); + } +} diff --git a/ios/Classes/UIColorHandler.h b/ios/Classes/UIColorHandler.h new file mode 100644 index 0000000..3b4a37e --- /dev/null +++ b/ios/Classes/UIColorHandler.h @@ -0,0 +1,15 @@ +// +// UIColorHandler.h +// foundation_fluttify +// +// Created by Yohom Bao on 2020/3/9. +// + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +void UIColorHandler(NSString* method, id args, FlutterResult methodResult); + +NS_ASSUME_NONNULL_END diff --git a/ios/Classes/UIColorHandler.m b/ios/Classes/UIColorHandler.m new file mode 100644 index 0000000..e1d9bc3 --- /dev/null +++ b/ios/Classes/UIColorHandler.m @@ -0,0 +1,29 @@ +// +// UIColorHandler.m +// foundation_fluttify +// +// Created by Yohom Bao on 2020/3/9. +// + +#import "UIColorHandler.h" + +extern BOOL enableLog; + +void UIColorHandler(NSString* method, id rawArgs, FlutterResult methodResult) { + if ([@"UIColor::create" isEqualToString:method]) { + NSDictionary* args = (NSDictionary*) rawArgs; + + NSNumber *colorValue = (NSNumber *) args[@"colorValue"]; + CGFloat alpha = (0xff000000 & [colorValue integerValue]) >> 24; + CGFloat red = (0x00ff0000 & [colorValue integerValue]) >> 16; + CGFloat green = (0x0000ff00 & [colorValue integerValue]) >> 8; + CGFloat blue = (0x000000ff & [colorValue integerValue]) >> 0; + + UIColor *color = [UIColor colorWithRed:red / 0xFF green:green / 0xFF blue:blue / 0xFF alpha:alpha / 0xFF]; + + methodResult(color); + } else { + methodResult(FlutterMethodNotImplemented); + } +} + diff --git a/ios/Classes/UIEdgeInsetsHandler.h b/ios/Classes/UIEdgeInsetsHandler.h new file mode 100644 index 0000000..78d20b3 --- /dev/null +++ b/ios/Classes/UIEdgeInsetsHandler.h @@ -0,0 +1,12 @@ +// +// Created by Yohom Bao on 2019/12/5. +// + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +void UIEdgeInsetsHandler(NSString* method, id args, FlutterResult methodResult); + +NS_ASSUME_NONNULL_END diff --git a/ios/Classes/UIEdgeInsetsHandler.m b/ios/Classes/UIEdgeInsetsHandler.m new file mode 100644 index 0000000..7a6846b --- /dev/null +++ b/ios/Classes/UIEdgeInsetsHandler.m @@ -0,0 +1,74 @@ +// +// Created by Yohom Bao on 2019/12/5. +// + +#import "UIEdgeInsetsHandler.h" + +extern BOOL enableLog; + +void UIEdgeInsetsHandler(NSString* method, id rawArgs, FlutterResult methodResult) { + if ([@"UIEdgeInsets::getTop" isEqualToString:method]) { + NSDictionary* args = (NSDictionary*) rawArgs; + + NSValue *target = (NSValue *) args[@"__this__"]; + if (target != nil && (NSNull*) target != [NSNull null]) { + UIEdgeInsets insets = [target UIEdgeInsetsValue]; + methodResult(@(insets.top)); + } else { + methodResult([FlutterError errorWithCode:@"目标对象为nul" + message:@"目标对象为nul" + details:@"目标对象为nul"]); + } + } else if ([@"UIEdgeInsets::getLeft" isEqualToString:method]) { + NSDictionary* args = (NSDictionary*) rawArgs; + + NSValue *target = (NSValue *) args[@"__this__"]; + if (target != nil && (NSNull*) target != [NSNull null]) { + UIEdgeInsets insets = [target UIEdgeInsetsValue]; + methodResult(@(insets.left)); + } else { + methodResult([FlutterError errorWithCode:@"目标对象为nul" + message:@"目标对象为nul" + details:@"目标对象为nul"]); + } + } else if ([@"UIEdgeInsets::getBottom" isEqualToString:method]) { + NSDictionary* args = (NSDictionary*) rawArgs; + + NSValue *target = (NSValue *) args[@"__this__"]; + if (target != nil && (NSNull*) target != [NSNull null]) { + UIEdgeInsets insets = [target UIEdgeInsetsValue]; + methodResult(@(insets.bottom)); + } else { + methodResult([FlutterError errorWithCode:@"目标对象为nul" + message:@"目标对象为nul" + details:@"目标对象为nul"]); + } + } else if ([@"UIEdgeInsets::getRight" isEqualToString:method]) { + NSDictionary* args = (NSDictionary*) rawArgs; + + NSValue *target = (NSValue *) args[@"__this__"]; + if (target != nil && (NSNull*) target != [NSNull null]) { + UIEdgeInsets insets = [target UIEdgeInsetsValue]; + methodResult(@(insets.right)); + } else { + methodResult([FlutterError errorWithCode:@"目标对象为nul" + message:@"目标对象为nul" + details:@"目标对象为nul"]); + } + } else if ([@"UIEdgeInsets::create" isEqualToString:method]) { + NSDictionary* args = (NSDictionary*) rawArgs; + + NSNumber *top = (NSNumber *) args[@"top"]; + NSNumber *left = (NSNumber *) args[@"left"]; + NSNumber *bottom = (NSNumber *) args[@"bottom"]; + NSNumber *right = (NSNumber *) args[@"right"]; + + UIEdgeInsets insets = UIEdgeInsetsMake([top floatValue], [left floatValue], [bottom floatValue], [right floatValue]); + + NSValue *valuePoint = [NSValue valueWithUIEdgeInsets:insets]; + + methodResult(valuePoint); + } else { + methodResult(FlutterMethodNotImplemented); + } +} diff --git a/ios/Classes/UIImageHandler.h b/ios/Classes/UIImageHandler.h new file mode 100644 index 0000000..04998ca --- /dev/null +++ b/ios/Classes/UIImageHandler.h @@ -0,0 +1,13 @@ +// +// Created by Yohom Bao on 2019/11/22. +// + +#import +#import +#import "FoundationFluttifyPlugin.h" + +NS_ASSUME_NONNULL_BEGIN + +void UIImageHandler(NSString* method, id args, FlutterResult methodResult); + +NS_ASSUME_NONNULL_END diff --git a/ios/Classes/UIImageHandler.m b/ios/Classes/UIImageHandler.m new file mode 100644 index 0000000..662a05b --- /dev/null +++ b/ios/Classes/UIImageHandler.m @@ -0,0 +1,69 @@ +// +// Created by Yohom Bao on 2019/11/22. +// + +#import "UIImageHandler.h" + +extern BOOL enableLog; + +void UIImageHandler(NSString *method, id rawArgs, FlutterResult methodResult) { + // UIImage::getData + if ([@"UIImage::getData" isEqualToString:method]) { + NSDictionary *args = (NSDictionary *) rawArgs; + + UIImage *target = (UIImage *) args[@"__this__"]; + if (target != nil && (NSNull*) target != [NSNull null]) { + NSData *data = UIImageJPEGRepresentation(target, 100); + methodResult([FlutterStandardTypedData typedDataWithBytes:data]); + } else { + methodResult([FlutterError errorWithCode:@"目标对象为nul" + message:@"目标对象为nul" + details:@"目标对象为nul"]); + } + } + // 创建UIImage + else if ([@"UIImage::createUIImage" isEqualToString:method]) { + NSDictionary *args = (NSDictionary *) rawArgs; + + FlutterStandardTypedData *bitmapBytes = (FlutterStandardTypedData *) args[@"bitmapBytes"]; + + UIImage *bitmap = [UIImage imageWithData:bitmapBytes.data scale:[UIScreen mainScreen].scale]; + + methodResult(bitmap); + } + // 创建UIImage + else if ([@"UIImage::createWithPath" isEqualToString:method]) { + NSDictionary *args = (NSDictionary *) rawArgs; + + NSString *resource = (NSString *) args[@"resource"]; + NSString *type = (NSString *) args[@"type"]; + NSString *fileName = (NSString *) args[@"fileName"]; + + NSString *path = [[NSBundle mainBundle] pathForResource:resource ofType:type]; + path = [path stringByAppendingPathComponent:fileName]; + + UIImage *bitmap = [UIImage imageWithContentsOfFile:path]; + + methodResult(bitmap); + } + // 批量创建UIImage + else if ([@"UIImage::createUIImage_batch" isEqualToString:method]) { + NSArray *> *argsBatch = (NSArray *> *) rawArgs; + + NSMutableArray *resultList = [NSMutableArray array]; + + for (NSUInteger __i__ = 0; __i__ < argsBatch.count; __i__++) { + NSDictionary *args = argsBatch[__i__]; + + FlutterStandardTypedData *bitmapBytes = (FlutterStandardTypedData *) args[@"bitmapBytes"]; + + UIImage *bitmap = [UIImage imageWithData:bitmapBytes.data scale:[UIScreen mainScreen].scale]; + + [resultList addObject:bitmap]; + } + + methodResult(resultList); + } else { + methodResult(FlutterMethodNotImplemented); + } +} diff --git a/ios/Classes/UIImageViewHandler.h b/ios/Classes/UIImageViewHandler.h new file mode 100644 index 0000000..e99d0ea --- /dev/null +++ b/ios/Classes/UIImageViewHandler.h @@ -0,0 +1,15 @@ +// +// UIImageViewHandler.h +// foundation_fluttify +// +// Created by Yohom Bao on 2020/7/2. +// + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +void UIImageViewHandler(NSString* method, id args, FlutterResult methodResult); + +NS_ASSUME_NONNULL_END diff --git a/ios/Classes/UIImageViewHandler.m b/ios/Classes/UIImageViewHandler.m new file mode 100644 index 0000000..08ddc2d --- /dev/null +++ b/ios/Classes/UIImageViewHandler.m @@ -0,0 +1,24 @@ +// +// UIImageViewHandler.m +// foundation_fluttify +// +// Created by Yohom Bao on 2020/7/2. +// + +#import "UIImageViewHandler.h" + +extern BOOL enableLog; + +void UIImageViewHandler(NSString *method, id rawArgs, FlutterResult methodResult) { + if ([@"UIImageView::create" isEqualToString:method]) { + NSDictionary *args = (NSDictionary *) rawArgs; + + UIImage *image = (UIImage *) args[@"image"]; + + UIImageView *imageView = [[UIImageView alloc] initWithImage:image]; + + methodResult(imageView); + } else { + methodResult(FlutterMethodNotImplemented); + } +} diff --git a/ios/Classes/UIViewControllerHandler.h b/ios/Classes/UIViewControllerHandler.h new file mode 100644 index 0000000..dbd03bc --- /dev/null +++ b/ios/Classes/UIViewControllerHandler.h @@ -0,0 +1,15 @@ +// +// UIViewControllerHandler.h +// foundation_fluttify +// +// Created by Yohom Bao on 2020/6/6. +// + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +void UIViewControllerHandler(NSString* method, id args, FlutterResult methodResult); + +NS_ASSUME_NONNULL_END diff --git a/ios/Classes/UIViewControllerHandler.m b/ios/Classes/UIViewControllerHandler.m new file mode 100644 index 0000000..0c21a1e --- /dev/null +++ b/ios/Classes/UIViewControllerHandler.m @@ -0,0 +1,21 @@ +// +// UIViewControllerHandler.m +// foundation_fluttify +// +// Created by Yohom Bao on 2020/6/6. +// + +#import "UIViewControllerHandler.h" +#import + +extern BOOL enableLog; + +void UIViewControllerHandler(NSString* method, id args, FlutterResult methodResult) { + if ([@"UIViewController::get" isEqualToString:method]) { + UIViewController* controller = [UIApplication sharedApplication].keyWindow.rootViewController; + + methodResult(controller); + } else { + methodResult(FlutterMethodNotImplemented); + } +} diff --git a/ios/Classes/UIViewHandler.h b/ios/Classes/UIViewHandler.h new file mode 100644 index 0000000..53e3bf5 --- /dev/null +++ b/ios/Classes/UIViewHandler.h @@ -0,0 +1,12 @@ +// +// Created by Yohom Bao on 2019/11/22. +// + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +void UIViewHandler(NSString* method, id args, FlutterResult methodResult); + +NS_ASSUME_NONNULL_END diff --git a/ios/Classes/UIViewHandler.m b/ios/Classes/UIViewHandler.m new file mode 100644 index 0000000..201f239 --- /dev/null +++ b/ios/Classes/UIViewHandler.m @@ -0,0 +1,210 @@ +// +// Created by Yohom Bao on 2019/11/22. +// + +#import +#import "UIViewHandler.h" + +extern BOOL enableLog; + +void UIViewHandler(NSString* method, id args, FlutterResult methodResult) { + // UIImage::getFrame + if ([@"UIView::getFrame" isEqualToString:method]) { + UIView *target = (UIView *) args[@"__this__"]; + if (target != nil && (NSNull*) target != [NSNull null]) { + CGRect rect = [target frame]; + NSValue *dataValue = [NSValue value:&rect withObjCType:@encode(CGRect)]; + methodResult(dataValue); + } else { + methodResult([FlutterError errorWithCode:@"目标对象为nul" + message:@"目标对象为nul" + details:@"目标对象为nul"]); + } + } else if ([@"UIView::getHidden" isEqualToString:method]) { + UIView *target = (UIView *) args[@"__this__"]; + if (target != nil && (NSNull*) target != [NSNull null]) { + methodResult(@(target.isHidden)); + } else { + methodResult([FlutterError errorWithCode:@"目标对象为nul" + message:@"目标对象为nul" + details:@"目标对象为nul"]); + } + } else if ([@"UIView::rotate" isEqualToString:method]) { + NSNumber* angle = (NSNumber*) args[@"angle"]; + + UIView *target = (UIView *) args[@"__this__"]; + if (target != nil && (NSNull*) target != [NSNull null]) { + target.transform = CGAffineTransformMakeRotation([angle doubleValue] / 180.0 * M_PI); + methodResult(@"success"); + } else { + methodResult([FlutterError errorWithCode:@"目标对象为nul" + message:@"目标对象为nul" + details:@"目标对象为nul"]); + } + } else if ([@"UIView::create" isEqualToString:method]) { + UIView* result = [[UIView alloc] init]; + methodResult(result); + } else if ([@"UIView::setHidden" isEqualToString:method]) { + NSNumber* hidden = (NSNumber*) args[@"hidden"]; + + UIView *target = (UIView *) args[@"__this__"]; + if (target != nil && (NSNull*) target != [NSNull null]) { + target.hidden = [hidden boolValue]; + methodResult(@"success"); + } else { + methodResult([FlutterError errorWithCode:@"目标对象为nul" + message:@"目标对象为nul" + details:@"目标对象为nul"]); + } + } else if ([@"UIView::setAnchorPoint" isEqualToString:method]) { + NSNumber* anchorU = (NSNumber*) args[@"anchorU"]; + NSNumber* anchorV = (NSNumber*) args[@"anchorV"]; + + UIView *target = (UIView *) args[@"__this__"]; + if (target != nil && (NSNull*) target != [NSNull null]) { + target.layer.anchorPoint = CGPointMake([anchorU doubleValue], [anchorV doubleValue]); + methodResult(@"success"); + } else { + methodResult([FlutterError errorWithCode:@"目标对象为nul" + message:@"目标对象为nul" + details:@"目标对象为nul"]); + } + } else if ([@"UIView::scaleWithDuration" isEqualToString:method]) { + NSNumber* duration = (NSNumber*) args[@"duration"]; + NSNumber* fromValue = (NSNumber*) args[@"fromValue"]; + NSNumber* toValue = (NSNumber*) args[@"toValue"]; + NSNumber* repeatCount = (NSNumber*) args[@"repeatCount"]; + NSNumber* repeatMode = (NSNumber*) args[@"repeatMode"]; + + UIView *target = (UIView *) args[@"__this__"]; + if (target != nil && (NSNull*) target != [NSNull null]) { + CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.scale"]; + animation.fromValue = fromValue; + animation.toValue = toValue; + animation.duration = [duration doubleValue]; + animation.autoreverses = [repeatMode intValue] == 0 ? NO : YES; + animation.repeatCount = [repeatCount intValue] == 0 ? MAXFLOAT : [repeatCount intValue]; + animation.removedOnCompletion = NO; + animation.fillMode = kCAFillModeForwards; + [target.layer addAnimation:animation forKey:@"zoom"]; + + methodResult(@"success"); + } else { + methodResult([FlutterError errorWithCode:@"目标对象为nul" + message:@"目标对象为nul" + details:@"目标对象为nul"]); + } + } else if ([@"UIView::translateWithDuration" isEqualToString:method]) { + NSNumber* duration = (NSNumber*) args[@"duration"]; + NSNumber* toX = (NSNumber*) args[@"toX"]; + NSNumber* toY = (NSNumber*) args[@"toY"]; + NSNumber* repeatCount = (NSNumber*) args[@"repeatCount"]; + NSNumber* repeatMode = (NSNumber*) args[@"repeatMode"]; + + UIView *target = (UIView *) args[@"__this__"]; + if (target != nil && (NSNull*) target != [NSNull null]) { + CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"]; + animation.toValue = [NSValue valueWithCGPoint:CGPointMake([toX floatValue], [toY floatValue])]; + animation.duration = [duration doubleValue]; + animation.autoreverses = [repeatMode intValue] == 0 ? NO : YES; + animation.repeatCount = [repeatCount intValue] == 0 ? MAXFLOAT : [repeatCount intValue]; + animation.removedOnCompletion = NO; + animation.fillMode = kCAFillModeForwards; + [target.layer addAnimation:animation forKey:@"position"]; + + methodResult(@"success"); + } else { + methodResult([FlutterError errorWithCode:@"目标对象为nul" + message:@"目标对象为nul" + details:@"目标对象为nul"]); + } + } else if ([@"UIView::alphaWithDuration" isEqualToString:method]) { + NSNumber* duration = (NSNumber*) args[@"duration"]; + NSNumber* fromValue = (NSNumber*) args[@"fromValue"]; + NSNumber* toValue = (NSNumber*) args[@"toValue"]; + NSNumber* repeatCount = (NSNumber*) args[@"repeatCount"]; + NSNumber* repeatMode = (NSNumber*) args[@"repeatMode"]; + + UIView *target = (UIView *) args[@"__this__"]; + if (target != nil && (NSNull*) target != [NSNull null]) { + CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"opacity"]; + animation.fromValue = fromValue; + animation.toValue = toValue; + animation.duration = [duration doubleValue]; + animation.autoreverses = [repeatMode intValue] == 0 ? NO : YES; + animation.repeatCount = [repeatCount intValue] == 0 ? MAXFLOAT : [repeatCount intValue]; + animation.removedOnCompletion = NO; + animation.fillMode = kCAFillModeForwards; + [target.layer addAnimation:animation forKey:@"opacity"]; + + methodResult(@"success"); + } else { + methodResult([FlutterError errorWithCode:@"目标对象为nul" + message:@"目标对象为nul" + details:@"目标对象为nul"]); + } + } else if ([@"UIView::rotateWithDuration" isEqualToString:method]) { + NSNumber* duration = (NSNumber*) args[@"duration"]; + NSNumber* fromValue = (NSNumber*) args[@"fromValue"]; + NSNumber* toValue = (NSNumber*) args[@"toValue"]; + NSNumber* repeatCount = (NSNumber*) args[@"repeatCount"]; + NSNumber* repeatMode = (NSNumber*) args[@"repeatMode"]; + + UIView *target = (UIView *) args[@"__this__"]; + if (target != nil && (NSNull*) target != [NSNull null]) { + CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"]; + animation.fromValue = fromValue; + animation.toValue = toValue; + animation.duration = [duration doubleValue]; + animation.autoreverses = [repeatMode intValue] == 0 ? NO : YES; + animation.repeatCount = [repeatCount intValue] == 0 ? MAXFLOAT : [repeatCount intValue]; + animation.removedOnCompletion = NO; + animation.fillMode = kCAFillModeForwards; + [target.layer addAnimation:animation forKey:@"rotation"]; + + methodResult(@"success"); + } else { + methodResult([FlutterError errorWithCode:@"目标对象为nul" + message:@"目标对象为nul" + details:@"目标对象为nul"]); + } + } else if ([@"UIView::groupWithDuration" isEqualToString:method]) { + NSNumber* duration = (NSNumber*) args[@"duration"]; + NSArray* fromValue = (NSArray*) args[@"fromValue"]; + NSArray* toValue = (NSArray*) args[@"toValue"]; + NSArray* keyPath = (NSArray*) args[@"keyPath"]; + NSNumber* repeatCount = (NSNumber*) args[@"repeatCount"]; + NSNumber* repeatMode = (NSNumber*) args[@"repeatMode"]; + + UIView *target = (UIView *) args[@"__this__"]; + if (target != nil && (NSNull*) target != [NSNull null]) { + NSMutableArray* animations = [NSMutableArray arrayWithCapacity:[fromValue count]]; + + for (NSUInteger i = 0; i < animations.count; i++) { + CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:keyPath[i]]; + animation.fromValue = fromValue[i]; + animation.toValue = toValue[i]; + + [animations addObject:animation]; + } + + CAAnimationGroup *group = [CAAnimationGroup animation]; + group.duration = [duration doubleValue]; + group.autoreverses = [repeatMode intValue] == 0 ? NO : YES; + group.repeatCount = [repeatCount intValue] == 0 ? MAXFLOAT : [repeatCount intValue]; + group.removedOnCompletion = NO; + group.fillMode = kCAFillModeForwards; + [group setAnimations:animations]; + + [target.layer addAnimation:group forKey:@"group"]; + + methodResult(@"success"); + } else { + methodResult([FlutterError errorWithCode:@"目标对象为nul" + message:@"目标对象为nul" + details:@"目标对象为nul"]); + } + } else { + methodResult(FlutterMethodNotImplemented); + } +} diff --git a/ios/Classes/platform_view/UIViewFactory.h b/ios/Classes/platform_view/UIViewFactory.h new file mode 100644 index 0000000..ab53060 --- /dev/null +++ b/ios/Classes/platform_view/UIViewFactory.h @@ -0,0 +1,29 @@ +// +// UIViewFactory.h +// foundation_fluttify +// +// Created by Yohom Bao on 2020/4/17. +// + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface UIViewFactory : NSObject + +- (instancetype)initWithRegistrar:(NSObject *)registrar; + +@property(nonatomic) NSObject* registrar; + +@end + +@interface UIViewPlatformView : NSObject + +- (instancetype)initWithViewId:(int64_t)viewId frame:(CGRect)frame registrar:(NSObject *)registrar; + +@property(nonatomic) NSObject* registrar; + +@end + +NS_ASSUME_NONNULL_END diff --git a/ios/Classes/platform_view/UIViewFactory.m b/ios/Classes/platform_view/UIViewFactory.m new file mode 100644 index 0000000..c96711d --- /dev/null +++ b/ios/Classes/platform_view/UIViewFactory.m @@ -0,0 +1,60 @@ +// +// UIViewFactory.m +// foundation_fluttify +// +// Created by Yohom Bao on 2020/4/17. +// + +#import "UIViewFactory.h" +#import "FoundationFluttifyPlugin.h" + +// Dart端随机存取对象的容器 +extern NSMutableDictionary *HEAP; + +@implementation UIViewFactory { +} + +- (instancetype)initWithRegistrar:(NSObject *)registrar { + self = [super init]; + if (self) { + _registrar = registrar; + } + + return self; +} + +- (NSObject *)createWithFrame:(CGRect)frame viewIdentifier:(int64_t)viewId arguments:(id _Nullable)args { + return [[UIViewPlatformView alloc] initWithViewId:viewId frame: frame registrar:_registrar]; +} + +@end + +@implementation UIViewPlatformView { + int64_t _viewId; + CGRect _frame; + UIView* _view; +} + +- (instancetype)initWithViewId:(int64_t)viewId frame:(CGRect)frame registrar:(NSObject *)registrar { + self = [super init]; + if (self) { + _viewId = viewId; + _registrar = registrar; + _frame = frame; + } + + return self; +} + +- (UIView *)view { + if (_view == nil) { + _view = [[UIView alloc] initWithFrame:_frame]; + } + // 这里用一个magic number调整一下id + HEAP[[NSString stringWithFormat:@"%@", @(2147483647 - _viewId)]] = _view; + HEAP[[NSString stringWithFormat:@"%@:%@", @"UIView", @(_view.hash)]] = _view; + return _view; +} + +@end + diff --git a/ios/foundation_fluttify.podspec b/ios/foundation_fluttify.podspec new file mode 100644 index 0000000..b719bc4 --- /dev/null +++ b/ios/foundation_fluttify.podspec @@ -0,0 +1,24 @@ +# +# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html +# +Pod::Spec.new do |s| + s.name = 'foundation_fluttify' + s.version = '0.0.1' + s.summary = 'A new Flutter project.' + s.description = <<-DESC +A new Flutter project. + DESC + s.homepage = 'http://example.com' + s.license = { :file => '../LICENSE' } + s.author = { 'Your Company' => 'email@example.com' } + s.source = { :path => '.' } + s.source_files = 'Classes/**/*' + s.public_header_files = 'Classes/**/*.h' + s.dependency 'Flutter' + + s.ios.deployment_target = '8.0' + s.static_framework = true + # 系统framework + s.frameworks = [] +end + diff --git a/lib/foundation_fluttify.dart b/lib/foundation_fluttify.dart new file mode 100644 index 0000000..28a2e10 --- /dev/null +++ b/lib/foundation_fluttify.dart @@ -0,0 +1,82 @@ +library foundation_fluttify; + +export 'src/extension/image_provider.x.dart'; +export 'src/function/functions.dart'; +export 'src/object/obejcts.dart'; +export 'src/type/core/array.dart'; +export 'src/type/core/broadcast_event_channel.dart'; +export 'src/type/core/fluttify_message_codec.dart'; +export 'src/type/core/ref.dart'; +export 'src/type/core/typedefs.dart'; +export 'src/type/platform/android_type/android/app/activity.dart'; +export 'src/type/platform/android_type/android/app/application.dart'; +export 'src/type/platform/android_type/android/app/notification.dart'; +export 'src/type/platform/android_type/android/app/pending_intent.dart'; +export 'src/type/platform/android_type/android/content/broadcast_receiver.dart'; +export 'src/type/platform/android_type/android/content/content_provider.dart'; +export 'src/type/platform/android_type/android/content/context.dart'; +export 'src/type/platform/android_type/android/content/intent.dart'; +export 'src/type/platform/android_type/android/content/intent_filter.dart'; +export 'src/type/platform/android_type/android/graphics/bitmap.dart'; +export 'src/type/platform/android_type/android/graphics/drawable/drawable.dart'; +export 'src/type/platform/android_type/android/graphics/point.dart'; +export 'src/type/platform/android_type/android/graphics/point_f.dart'; +export 'src/type/platform/android_type/android/location/location.dart'; +export 'src/type/platform/android_type/android/opengl/gl_surface_view.dart'; +export 'src/type/platform/android_type/android/os/binder.dart'; +export 'src/type/platform/android_type/android/os/bundle.dart'; +export 'src/type/platform/android_type/android/os/parcelable.dart'; +export 'src/type/platform/android_type/android/util/pair.dart'; +export 'src/type/platform/android_type/android/view/motion_event.dart'; +export 'src/type/platform/android_type/android/view/surface_holder.dart'; +export 'src/type/platform/android_type/android/view/surface_view.dart'; +export 'src/type/platform/android_type/android/view/view.dart'; +export 'src/type/platform/android_type/android/view/view_group.dart'; +export 'src/type/platform/android_type/android/widget/frame_layout.dart'; +export 'src/type/platform/android_type/android/widget/image_view.dart'; +export 'src/type/platform/android_type/android/widget/linear_layout.dart'; +export 'src/type/platform/android_type/android/widget/relative_layout.dart'; +export 'src/type/platform/android_type/android/widget/text_view.dart'; +export 'src/type/platform/android_type/java/io/closeable.dart'; +export 'src/type/platform/android_type/java/io/file.dart'; +export 'src/type/platform/android_type/java/io/serializable.dart'; +export 'src/type/platform/android_type/java/lang/object.dart'; +export 'src/type/platform/android_type/java/lang/throwable.dart'; +export 'src/type/platform/android_type/org/json/json_object.dart'; +export 'src/type/platform/ios_type/av_audio_session_category_options.dart'; +export 'src/type/platform/ios_type/ca_action.dart'; +export 'src/type/platform/ios_type/ca_animation.dart'; +export 'src/type/platform/ios_type/ca_basic_animation.dart'; +export 'src/type/platform/ios_type/ca_media_timing.dart'; +export 'src/type/platform/ios_type/ca_property_animation.dart'; +export 'src/type/platform/ios_type/cg_point.dart'; +export 'src/type/platform/ios_type/cg_rect.dart'; +export 'src/type/platform/ios_type/cg_size.dart'; +export 'src/type/platform/ios_type/ns_coding.dart'; +export 'src/type/platform/ios_type/ns_copying.dart'; +export 'src/type/platform/ios_type/ns_data.dart'; +export 'src/type/platform/ios_type/ns_date.dart'; +export 'src/type/platform/ios_type/ns_error.dart'; +export 'src/type/platform/ios_type/ns_mutable_copying.dart'; +export 'src/type/platform/ios_type/ns_object.dart'; +export 'src/type/platform/ios_type/ns_operation.dart'; +export 'src/type/platform/ios_type/ns_url.dart'; +export 'src/type/platform/ios_type/ns_user_activity.dart'; +export 'src/type/platform/ios_type/ns_value.dart'; +export 'src/type/platform/ios_type/ui_application.dart'; +export 'src/type/platform/ios_type/ui_application_shortcut_item.dart'; +export 'src/type/platform/ios_type/ui_bar_style.dart'; +export 'src/type/platform/ios_type/ui_color.dart'; +export 'src/type/platform/ios_type/ui_control.dart'; +export 'src/type/platform/ios_type/ui_edge_insets.dart'; +export 'src/type/platform/ios_type/ui_image.dart'; +export 'src/type/platform/ios_type/ui_image_view.dart'; +export 'src/type/platform/ios_type/ui_status_bar_style.dart'; +export 'src/type/platform/ios_type/ui_user_notification_settings.dart'; +export 'src/type/platform/ios_type/ui_view.dart'; +export 'src/type/platform/ios_type/ui_view_controller.dart'; +export 'src/type/widget/android_opengl_GLSurfaceView.widget.dart'; +export 'src/type/widget/android_view_SurfaceView.widget.dart'; +export 'src/type/widget/android_widget_FrameLayout.widget.dart'; +export 'src/type/widget/scoped_release_pool.widget.dart'; +export 'src/type/widget/ui_view.widget.dart'; diff --git a/lib/src/extension/image_provider.x.dart b/lib/src/extension/image_provider.x.dart new file mode 100644 index 0000000..3054fdd --- /dev/null +++ b/lib/src/extension/image_provider.x.dart @@ -0,0 +1,36 @@ +import 'dart:async'; +import 'dart:typed_data'; +import 'dart:ui'; + +import 'package:flutter/material.dart'; + +Map _cache = {}; + +extension ImageProviderX on ImageProvider { + Future toImageData(ImageConfiguration config) async { + final completer = Completer(); + final key = await obtainKey(config); + if (_cache.containsKey(key.toString())) { + debugPrint('命中缓存'); + completer.complete(_cache[key.toString()]); + } else { + late ImageStreamListener listener; + ImageStream stream = resolve(config); //获取图片流 + listener = ImageStreamListener((imageInfo, sync) async { + final byteData = + await imageInfo.image.toByteData(format: ImageByteFormat.png); + final result = byteData?.buffer.asUint8List(); + if (result != null) { + _cache[key.toString()] = result; + } + + if (!completer.isCompleted) completer.complete(result); + + stream.removeListener(listener); //移除监听 + }); + stream.addListener(listener); + } + + return completer.future; + } +} diff --git a/lib/src/function/functions.dart b/lib/src/function/functions.dart new file mode 100644 index 0000000..9528966 --- /dev/null +++ b/lib/src/function/functions.dart @@ -0,0 +1,255 @@ +import 'dart:async'; +import 'dart:io'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/foundation.dart'; + +import '../../foundation_fluttify.dart'; + +typedef _FutureCallback = Future Function(Set releasePool); + +bool _enableFluttifyLog = true; +Future enableFluttifyLog(bool enable) { + _enableFluttifyLog = enable; + return kMethodChannel.invokeMethod('PlatformService::enableLog', { + 'enable': enable, + }); +} + +bool get fluttifyLogEnabled => _enableFluttifyLog; + +Future platform({ + _FutureCallback? android, + _FutureCallback? ios, +}) async { + // 方法单位的释放池, 如果需要的时候可以在这里直接释放, 不使用这个释放池的话可以使用[ScopedReleasePool] + final releasePool = {}; + try { + if (android != null && Platform.isAndroid) { + return await android(releasePool); + } else if (ios != null && Platform.isIOS) { + return await ios(releasePool); + } else { + return Future.value(); + } + } catch (e) { + return Future.error(e); + } finally { + if (releasePool.isNotEmpty) { + await releasePool.whereType().release_batch(); + releasePool.clear(); + // remove all local object from global object pool + gGlobalReleasePool.removeAll(releasePool); + } + } +} + +Future clearHeap() async { + await kMethodChannel.invokeMethod('PlatformService::clearHeap'); +} + +Future pushStack(String name, Ref ref) async { + await kMethodChannel.invokeMethod( + 'PlatformService::pushStack', + {'name': name, '__this__': ref}, + ); +} + +Future pushStackJsonable(String name, dynamic jsonable) async { + await kMethodChannel.invokeMethod('PlatformService::pushStackJsonable', { + 'name': name, + 'data': jsonable, + }); +} + +Future clearStack() async { + await kMethodChannel.invokeMethod('PlatformService::clearStack'); +} + +Future setupOrientationSensor() async { + await kMethodChannel.invokeMethod('PlatformService::setupOrientationSensor'); +} + +Future startActivity( + String activityClass, { + Map extras = const {}, +}) async { + assert(activityClass.isNotEmpty); + await kMethodChannel.invokeMethod( + 'PlatformService::startActivity', + {'activityClass': activityClass, 'extras': extras}, + ); +} + +Future startActivityForResult( + String activityClass, { + required int requestCode, + Map extras = const {}, +}) async { + assert(activityClass.isNotEmpty); + final result = await kMethodChannel.invokeMethod( + 'PlatformService::startActivityForResult', + { + 'activityClass': activityClass, + 'extras': extras, + 'requestCode': requestCode, + }, + ); + return android_content_Intent() + ..refId = result + ..tag__ = 'platform'; +} + +Future presentViewController( + String viewControllerClass, { + bool withNavigationController = false, +}) async { + assert(viewControllerClass.isNotEmpty); + await kMethodChannel.invokeMethod( + 'PlatformService::presentViewController', + { + 'viewControllerClass': viewControllerClass, + 'withNavigationController': withNavigationController, + }, + ); +} + +/// viewId转换为refId +/// +/// 使用这个方法前, 保存PlatformView是把viewId作为key保存在Map中, 带来了不一致性. +/// 使用这个方法把viewId转换为对应PlatformView对象的refId, 使其与普通对象的行为保持一致. +Future viewId2RefId(String viewId) async { + return kMethodChannel.invokeMethod( + 'PlatformService::viewId2RefId', + {'viewId': viewId}, + ); +} + +/// 不怎么好用 +@deprecated +Future getAssetPath(String flutterAssetPath) async { + return kMethodChannel.invokeMethod( + 'PlatformService::getAssetPath', + {'flutterAssetPath': flutterAssetPath}, + ); +} + +void log(String content) { + if (fluttifyLogEnabled) debugPrint(content); +} + +T? FoundationFluttifyAndroidAs(dynamic __this__) { + if (T == android_content_Context) { + return (android_content_Context()..refId = (__this__ as Ref).refId) as T; + } else if (T == android_content_Intent) { + return (android_content_Intent()..refId = (__this__ as Ref).refId) as T; + } else if (T == android_content_ContentProvider) { + return (android_content_ContentProvider()..refId = (__this__ as Ref).refId) + as T; + } else if (T == android_app_Application) { + return (android_app_Application()..refId = (__this__ as Ref).refId) as T; + } else if (T == android_app_Notification) { + return (android_app_Notification()..refId = (__this__ as Ref).refId) as T; + } else if (T == android_app_Activity) { + return (android_app_Activity()..refId = (__this__ as Ref).refId) as T; + } else if (T == android_app_PendingIntent) { + return (android_app_PendingIntent()..refId = (__this__ as Ref).refId) as T; + } else if (T == android_os_Bundle) { + return (android_os_Bundle()..refId = (__this__ as Ref).refId) as T; + } else if (T == android_os_Binder) { + return (android_os_Binder()..refId = (__this__ as Ref).refId) as T; + } else if (T == android_view_View) { + return (android_view_View()..refId = (__this__ as Ref).refId) as T; + } else if (T == android_view_SurfaceView) { + return (android_view_SurfaceView()..refId = (__this__ as Ref).refId) as T; + } else if (T == android_view_SurfaceHolder) { + return (android_view_SurfaceHolder.subInstance() + ..refId = (__this__ as Ref).refId) as T; + } else if (T == android_opengl_GLSurfaceView) { + return (android_opengl_GLSurfaceView()..refId = (__this__ as Ref).refId) + as T; + } else if (T == android_view_View_OnApplyWindowInsetsListener) { + return (android_view_View_OnApplyWindowInsetsListener.subInstance() + ..refId = (__this__ as Ref).refId) as T; + } else if (T == android_view_ViewGroup) { + return (android_view_ViewGroup()..refId = (__this__ as Ref).refId) as T; + } else if (T == android_graphics_Point) { + return (android_graphics_Point()..refId = (__this__ as Ref).refId) as T; + } else if (T == android_graphics_PointF) { + return (android_graphics_PointF()..refId = (__this__ as Ref).refId) as T; + } else if (T == android_graphics_Bitmap) { + return (android_graphics_Bitmap()..refId = (__this__ as Ref).refId) as T; + } else if (T == android_widget_ImageView) { + return (android_widget_ImageView()..refId = (__this__ as Ref).refId) as T; + } else if (T == java_io_Serializable) { + return (java_io_Serializable.subInstance()..refId = (__this__ as Ref).refId) + as T; + } else if (T == java_io_File) { + return (java_io_File()..refId = (__this__ as Ref).refId) as T; + } else if (T == android_location_Location) { + return (android_location_Location()..refId = (__this__ as Ref).refId) as T; + } else if (T == android_view_MotionEvent) { + return (android_view_MotionEvent()..refId = (__this__ as Ref).refId) as T; + } else if (T == android_graphics_drawable_Drawable) { + return (android_graphics_drawable_Drawable() + ..refId = (__this__ as Ref).refId) as T; + } else if (T == android_widget_FrameLayout) { + return (android_widget_FrameLayout()..refId = (__this__ as Ref).refId) as T; + } else if (T == android_widget_TextView) { + return (android_widget_TextView()..refId = (__this__ as Ref).refId) as T; + } else if (T == android_widget_LinearLayout) { + return (android_widget_LinearLayout()..refId = (__this__ as Ref).refId) + as T; + } else if (T == android_widget_RelativeLayout) { + return (android_widget_RelativeLayout()..refId = (__this__ as Ref).refId) + as T; + } else if (T == android_os_Parcelable) { + return (android_os_Parcelable.subInstance() + ..refId = (__this__ as Ref).refId) as T; + } else if (T == android_util_Pair) { + return (android_util_Pair()..refId = (__this__ as Ref).refId) as T; + } else { + return null; + } +} + +T? FoundationFluttifyIOSAs(dynamic __this__) { + if (T == CGRect) { + return (CGRect()..refId = (__this__ as Ref).refId) as T; + } else if (T == CGPoint) { + return (CGPoint()..refId = (__this__ as Ref).refId) as T; + } else if (T == CGSize) { + return (CGSize()..refId = (__this__ as Ref).refId) as T; + } else if (T == UIEdgeInsets) { + return (UIEdgeInsets()..refId = (__this__ as Ref).refId) as T; + } else if (T == NSError) { + return (NSError()..refId = (__this__ as Ref).refId) as T; + } else if (T == NSCoding) { + return (NSCoding.subInstance()..refId = (__this__ as Ref).refId) as T; + } else if (T == NSCopying) { + return (NSCopying.subInstance()..refId = (__this__ as Ref).refId) as T; + } else if (T == NSMutableCopying) { + return (NSMutableCopying.subInstance()..refId = (__this__ as Ref).refId) + as T; + } else if (T == UIView) { + return (UIView()..refId = (__this__ as Ref).refId) as T; + } else if (T == UIViewController) { + return (UIViewController()..refId = (__this__ as Ref).refId) as T; + } else if (T == UIControl) { + return (UIControl()..refId = (__this__ as Ref).refId) as T; + } else if (T == UIImage) { + return (UIImage()..refId = (__this__ as Ref).refId) as T; + } else if (T == UIImageView) { + return (UIImageView()..refId = (__this__ as Ref).refId) as T; + } else if (T == UIColor) { + return (UIColor()..refId = (__this__ as Ref).refId) as T; + } else if (T == NSData) { + return (NSData()..refId = (__this__ as Ref).refId) as T; + } else if (T == NSDate) { + return (NSDate()..refId = (__this__ as Ref).refId) as T; + } else if (T == NSOperation) { + return (NSOperation()..refId = (__this__ as Ref).refId) as T; + } else { + return null; + } +} diff --git a/lib/src/object/obejcts.dart b/lib/src/object/obejcts.dart new file mode 100644 index 0000000..a1bdf00 --- /dev/null +++ b/lib/src/object/obejcts.dart @@ -0,0 +1,197 @@ +import 'package:flutter/services.dart'; +import 'package:foundation_fluttify/foundation_fluttify.dart'; +import 'package:foundation_fluttify/src/type/core/ref.dart'; +import 'package:foundation_fluttify/src/type/core/stack.dart'; +import 'package:foundation_fluttify/src/type/core/typedefs.dart'; + +/// native object release pool, all objects returned by the native side will be in this set +final gGlobalReleasePool = {}; + +final gReleasePoolStack = Stack(); + +const kMethodChannelName = 'com.fluttify/foundation_method'; +const kMethodCodec = StandardMethodCodec(FluttifyMessageCodec()); +final kMethodChannel = MethodChannel(kMethodChannelName, kMethodCodec) + ..setMethodCallHandler((call) async { + final method = call.method; + final arguments = call.arguments as Map; + + final application = UIApplication()..refId = arguments['application']; + switch (method) { + case 'applicationDidFinishLaunchingWithOptions': + if (applicationDidFinishLaunchingWithOptions != null) { + final launchOptions = arguments['launchOptions'] as Map; + applicationDidFinishLaunchingWithOptions!(application, launchOptions); + } + break; + case 'applicationWillFinishLaunchingWithOptions': + if (applicationWillFinishLaunchingWithOptions != null) { + final launchOptions = arguments['launchOptions'] as Map; + applicationWillFinishLaunchingWithOptions!( + application, launchOptions); + } + break; + case 'applicationDidBecomeActive': + if (applicationDidBecomeActive != null) { + applicationDidBecomeActive!(application); + } + break; + case 'applicationWillResignActive': + if (applicationWillResignActive != null) { + applicationWillResignActive!(application); + } + break; + case 'applicationDidEnterBackground': + if (applicationDidEnterBackground != null) { + applicationDidEnterBackground!(application); + } + break; + case 'applicationWillEnterForeground': + if (applicationWillEnterForeground != null) { + applicationWillEnterForeground!(application); + } + break; + case 'applicationWillTerminate': + if (applicationWillTerminate != null) { + applicationWillTerminate!(application); + } + break; + case 'applicationDidRegisterUserNotificationSettings': + if (applicationDidRegisterUserNotificationSettings != null) { + final notificationSettings = UIUserNotificationSettings() + ..refId = arguments['notificationSettings']; + + applicationDidRegisterUserNotificationSettings!( + application, notificationSettings); + } + break; + case 'applicationDidRegisterForRemoteNotificationsWithDeviceToken': + if (applicationDidRegisterForRemoteNotificationsWithDeviceToken != + null) { + final deviceToken = NSData()..refId = arguments['deviceToken']; + + applicationDidRegisterForRemoteNotificationsWithDeviceToken!( + application, deviceToken); + } + break; + case 'applicationDidReceiveRemoteNotificationFetchCompletionHandler': + if (applicationDidReceiveRemoteNotificationFetchCompletionHandler != + null) { + final userInfo = arguments['userInfo'] as Map; + applicationDidReceiveRemoteNotificationFetchCompletionHandler!( + application, userInfo); + } + break; + case 'applicationOpenURLOptions': + if (applicationOpenURLOptions != null) { + final url = NSURL()..refId = arguments['url']; + final options = (arguments['options'] as Map).cast(); + applicationOpenURLOptions!(application, url, options); + } + break; + case 'applicationHandleOpenURL': + if (applicationHandleOpenURL != null) { + final url = NSURL()..refId = arguments['url']; + applicationHandleOpenURL!(application, url); + } + break; + case 'applicationOpenURLSourceApplicationAnnotation': + if (applicationOpenURLSourceApplicationAnnotation != null) { + final openURL = NSURL()..refId = arguments['openURL']; + final sourceApplication = arguments['sourceApplication'] as String; + final annotation = NSObject()..refId = arguments['annotation']; + + applicationOpenURLSourceApplicationAnnotation!( + application, + openURL, + sourceApplication, + annotation, + ); + } + break; + case 'applicationPerformActionForShortcutItemCompletionHandler': + if (applicationPerformActionForShortcutItemCompletionHandler != null) { + final shortcutItem = UIApplicationShortcutItem() + ..refId = arguments['shortcutItem']; + + applicationPerformActionForShortcutItemCompletionHandler!( + application, shortcutItem); + } + break; + case 'applicationHandleEventsForBackgroundURLSessionCompletionHandler': + if (applicationHandleEventsForBackgroundURLSessionCompletionHandler != + null) { + final identifier = arguments['identifier'] as String; + + applicationHandleEventsForBackgroundURLSessionCompletionHandler!( + application, identifier); + } + break; + case 'applicationPerformFetchWithCompletionHandler': + applicationPerformFetchWithCompletionHandler?.call(application); + + break; + case 'applicationContinueUserActivityRestorationHandler': + if (applicationContinueUserActivityRestorationHandler != null) { + final userActivity = NSUserActivity() + ..refId = arguments['userActivity']; + + applicationContinueUserActivityRestorationHandler!( + application, userActivity); + } + break; + default: + return Future.error('not implemented'); + } + }); + +const kBroadcastEventChannelName = 'com.fluttify/foundation_broadcast_event'; +const kBroadcastEventChannel = + FluttifyBroadcastEventChannel(kBroadcastEventChannelName); + +const kSensorEventChannelName = 'com.fluttify/foundation_sensor_event'; +const kSensorEventChannel = EventChannel(kSensorEventChannelName); + +ApplicationDidFinishLaunchingWithOptions? + applicationDidFinishLaunchingWithOptions; + +ApplicationWillFinishLaunchingWithOptions? + applicationWillFinishLaunchingWithOptions; + +ApplicationDidBecomeActive? applicationDidBecomeActive; + +ApplicationWillResignActive? applicationWillResignActive; + +ApplicationDidEnterBackground? applicationDidEnterBackground; + +ApplicationWillEnterForeground? applicationWillEnterForeground; + +ApplicationWillTerminate? applicationWillTerminate; + +ApplicationDidRegisterUserNotificationSettings? + applicationDidRegisterUserNotificationSettings; + +ApplicationDidRegisterForRemoteNotificationsWithDeviceToken? + applicationDidRegisterForRemoteNotificationsWithDeviceToken; + +ApplicationDidReceiveRemoteNotificationFetchCompletionHandler? + applicationDidReceiveRemoteNotificationFetchCompletionHandler; + +ApplicationOpenURLOptions? applicationOpenURLOptions; + +ApplicationHandleOpenURL? applicationHandleOpenURL; + +ApplicationOpenURLSourceApplicationAnnotation? + applicationOpenURLSourceApplicationAnnotation; + +ApplicationPerformActionForShortcutItemCompletionHandler? + applicationPerformActionForShortcutItemCompletionHandler; + +ApplicationHandleEventsForBackgroundURLSessionCompletionHandler? + applicationHandleEventsForBackgroundURLSessionCompletionHandler; + +ApplicationPerformFetchWithCompletionHandler? + applicationPerformFetchWithCompletionHandler; + +ApplicationContinueUserActivityRestorationHandler? + applicationContinueUserActivityRestorationHandler; diff --git a/lib/src/type/core/array.dart b/lib/src/type/core/array.dart new file mode 100644 index 0000000..1ed4456 --- /dev/null +++ b/lib/src/type/core/array.dart @@ -0,0 +1,5 @@ +class Array { + Array.ofList(this.data); + + final List data; +} diff --git a/lib/src/type/core/broadcast_event_channel.dart b/lib/src/type/core/broadcast_event_channel.dart new file mode 100644 index 0000000..0f2507c --- /dev/null +++ b/lib/src/type/core/broadcast_event_channel.dart @@ -0,0 +1,13 @@ +import 'package:flutter/services.dart'; +import 'package:foundation_fluttify/src/type/platform/android_type/android/content/intent.dart'; + +class FluttifyBroadcastEventChannel extends EventChannel { + const FluttifyBroadcastEventChannel(String name) : super(name); + + @override + Stream receiveBroadcastStream([dynamic arguments]) { + return super + .receiveBroadcastStream(arguments) + .map((event) => android_content_Intent()..refId = event); + } +} diff --git a/lib/src/type/core/fluttify_message_codec.dart b/lib/src/type/core/fluttify_message_codec.dart new file mode 100644 index 0000000..ae5fa08 --- /dev/null +++ b/lib/src/type/core/fluttify_message_codec.dart @@ -0,0 +1,210 @@ +import 'dart:convert'; +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/services.dart'; +import 'package:foundation_fluttify/foundation_fluttify.dart'; +import 'package:foundation_fluttify/src/type/core/array.dart'; + +class FluttifyMessageCodec extends StandardMessageCodec { + const FluttifyMessageCodec({ + this.tag, + this.androidCaster, + this.iosCaster, + }); + + final String? tag; + + /// 外部传入造型回调, 自动把Ref转换为目标对象 + /// foundation内部还是手动处理 + final dynamic Function(dynamic ref, String typeName)? androidCaster; + final dynamic Function(dynamic ref, String typeName)? iosCaster; + + static const int _valueNull = 0; + static const int _valueTrue = 1; + static const int _valueFalse = 2; + static const int _valueInt32 = 3; + static const int _valueInt64 = 4; + static const int _valueLargeInt = 5; + static const int _valueFloat64 = 6; + static const int _valueString = 7; + static const int _valueUint8List = 8; + static const int _valueInt32List = 9; + static const int _valueInt64List = 10; + static const int _valueFloat64List = 11; + static const int _valueList = 12; + static const int _valueMap = 13; + // Fluttify使用 Android only + static const int _valueArray = 125; + // Fluttify使用 + static const int _valueEnum = 126; + // 虽然dart端说明自定义类型要用128以上的值, 但是Java那边是用byte接收, 128已经超出, 所以 + // 这里直接使用127了, 肯定不会与flutter本身的类型冲突 + static const int _valueRef = 127; + + @override + void writeValue(WriteBuffer buffer, dynamic value) { + if (value == null || (value is Ref && value.refId == null)) { + buffer.putUint8(_valueNull); + } else if (value is bool) { + buffer.putUint8(value ? _valueTrue : _valueFalse); + } else if (value is double) { + // Double precedes int because in JS everything is a double. + // Therefore in JS, both `is int` and `is double` always + // return `true`. If we check int first, we'll end up treating + // all numbers as ints and attempt the int32/int64 conversion, + // which is wrong. This precedence rule is irrelevant when + // decoding because we use tags to detect the type of value. + buffer.putUint8(_valueFloat64); + buffer.putFloat64(value); + } else if (value is int) { + if (-0x7fffffff - 1 <= value && value <= 0x7fffffff) { + buffer.putUint8(_valueInt32); + buffer.putInt32(value); + } else { + buffer.putUint8(_valueInt64); + buffer.putInt64(value); + } + } else if (value is String) { + buffer.putUint8(_valueString); + final Uint8List bytes = utf8.encoder.convert(value); + writeSize(buffer, bytes.length); + buffer.putUint8List(bytes); + } else if (value is Uint8List) { + buffer.putUint8(_valueUint8List); + writeSize(buffer, value.length); + buffer.putUint8List(value); + } else if (value is Int32List) { + buffer.putUint8(_valueInt32List); + writeSize(buffer, value.length); + buffer.putInt32List(value); + } else if (value is Int64List) { + buffer.putUint8(_valueInt64List); + writeSize(buffer, value.length); + buffer.putInt64List(value); + } else if (value is Float64List) { + buffer.putUint8(_valueFloat64List); + writeSize(buffer, value.length); + buffer.putFloat64List(value); + } else if (value is Array) { + buffer.putUint8(_valueArray); + writeSize(buffer, value.data.length); + for (final dynamic item in value.data) { + writeValue(buffer, item); + } + } else if (value is Iterable) { + buffer.putUint8(_valueList); + writeSize(buffer, value.length); + for (final dynamic item in value) { + writeValue(buffer, item); + } + } else if (value is Map) { + buffer.putUint8(_valueMap); + writeSize(buffer, value.length); + value.forEach((dynamic key, dynamic value) { + writeValue(buffer, key); + writeValue(buffer, value); + }); + } + // 以下为fluttify增加的类型 + // 枚举 传递索引值 + else if (value is Enum) { + buffer.putUint8(_valueEnum); + buffer.putInt32(value.index); + } + // fluttify Ref类 + else if (value is Ref) { + buffer.putUint8(_valueRef); + final Uint8List bytes = utf8.encoder.convert(value.refId!); + writeSize(buffer, bytes.length); + buffer.putUint8List(bytes); + } else { + throw ArgumentError.value(value); + } + } + + @override + dynamic readValueOfType(int type, ReadBuffer buffer) { + switch (type) { + case _valueNull: + return null; + case _valueTrue: + return true; + case _valueFalse: + return false; + case _valueInt32: + return buffer.getInt32(); + case _valueInt64: + return buffer.getInt64(); + case _valueFloat64: + return buffer.getFloat64(); + case _valueLargeInt: + case _valueString: + final int length = readSize(buffer); + return utf8.decoder.convert(buffer.getUint8List(length)); + case _valueUint8List: + final int length = readSize(buffer); + return buffer.getUint8List(length); + case _valueInt32List: + final int length = readSize(buffer); + return buffer.getInt32List(length); + case _valueInt64List: + final int length = readSize(buffer); + return buffer.getInt64List(length); + case _valueFloat64List: + final int length = readSize(buffer); + return buffer.getFloat64List(length); + case _valueArray: + final int length = readSize(buffer); + final dynamic result = + List.filled(length, null, growable: false); + for (int i = 0; i < length; i++) { + result[i] = readValue(buffer); + } + return result; + case _valueList: + final int length = readSize(buffer); + final dynamic result = + List.filled(length, null, growable: false); + for (int i = 0; i < length; i++) { + result[i] = readValue(buffer); + } + return result; + case _valueMap: + final int length = readSize(buffer); + final dynamic result = {}; + for (int i = 0; i < length; i++) { + result[readValue(buffer)] = readValue(buffer); + } + return result; + case _valueEnum: + return buffer.getInt32(); + case _valueRef: + final int length = readSize(buffer); + final String refId = utf8.decoder.convert(buffer.getUint8List(length)); + + Ref ref = Ref() + ..refId = refId + ..tag__ = tag; + if (Platform.isAndroid && androidCaster != null) { + ref = androidCaster!(ref, refId.split(':')[0]); + } else if (Platform.isIOS && iosCaster != null) { + ref = iosCaster!(ref, refId.split(':')[0]); + } + + // 如果有ScopedReleasePool, 则使用ScopedReleasePool里的释放池 + // 否则使用全局的释放池 + if (gReleasePoolStack.peek() != null) { + log('添加对象 $ref 到局部释放池'); + gReleasePoolStack.peek()?.add(ref); + } else { + log('添加对象 $ref 到全局释放池'); + gGlobalReleasePool.add(ref); + } + return ref; + default: + throw const FormatException('Message corrupted'); + } + } +} diff --git a/lib/src/type/core/ref.dart b/lib/src/type/core/ref.dart new file mode 100644 index 0000000..6ce3656 --- /dev/null +++ b/lib/src/type/core/ref.dart @@ -0,0 +1,195 @@ +import 'package:foundation_fluttify/src/object/obejcts.dart'; + +class Ref { + /// unique id of native side counterpart object + String? refId; + + /// custom tag + String? tag__; + + /// 释放当前引用对象 + Future release__() async { + // 这里使用refId去删除元素, 因为PlatformView和普通对象的键不同, 不是hashCode, 原生端不能 + // 通过获取hash的方式删除元素 + await kMethodChannel + .invokeMethod('PlatformService::release', {'__this__': refId}); + } + + Future isNull() { + return kMethodChannel + .invokeMethod('PlatformService::isNull', {'__this__': this}); + } + + /// 通过反射调用方法 + Future performSelectorWithObject__(String selector, Object object) { + return kMethodChannel + .invokeMethod('PlatformService::performSelectorWithObject', { + '__this__': this, + 'selector': selector, + 'object': object, + }); + } + + /// 为类型添加属性 + Future addProperty__(int propertyKey, Ref property) async { + assert(property is Ref); + assert(propertyKey > 0); + return kMethodChannel.invokeMethod('PlatformService::addProperty', { + '__this__': this, + 'propertyKey': propertyKey, + 'property': property, + }); + } + + /// 为类型添加属性 + Future addListProperty__(int propertyKey, List property) async { + assert(propertyKey > 0); + return kMethodChannel.invokeMethod('PlatformService::addListProperty', { + '__this__': this, + 'propertyKey': propertyKey, + 'property': property, + }); + } + + /// 获取添加字段的值 + Future getProperty__(int propertyKey) async { + assert(propertyKey > 0); + final result = + await kMethodChannel.invokeMethod('PlatformService::getProperty', { + '__this__': this, + 'propertyKey': propertyKey, + }); + return Ref()..refId = result; + } + + /// 为类型添加jsonable属性 + Future addJsonableProperty__(int propertyKey, Object property) async { + assert(propertyKey > 0); + assert(property is String || + property is int || + property is double || + property is Map || + property is List || + property is bool); + return kMethodChannel.invokeMethod('PlatformService::addJsonableProperty', { + '__this__': this, + 'propertyKey': propertyKey, + 'property': property, + }); + } + + /// 获取添加字段的jsonable值 + Future getJsonableProperty__(int propertyKey) async { + assert(propertyKey > 0); + return kMethodChannel.invokeMethod('PlatformService::getJsonableProperty', { + '__this__': this, + 'propertyKey': propertyKey, + }); + } + + /// 转换为批处理 + List asBatch(int length) { + assert(length > 0); + return List.filled(length, this as T); + } + + @override + bool operator ==(Object other) => + identical(this, other) || + other is Ref && runtimeType == other.runtimeType && refId == other.refId; + + @override + int get hashCode => refId.hashCode; + + @override + String toString() { + return 'Ref{refId: $refId, runtimeType: $runtimeType, tag__: $tag__}'; + } +} + +extension Ref_Batch on Iterable { + // 这里使用refId去删除元素, 因为PlatformView和普通对象的键不同, 不是hashCode, 原生端不能 + // 通过获取hash的方式删除元素 + Future release_batch() async { + return kMethodChannel.invokeMethod( + 'PlatformService::release_batch', + {'__this_batch__': map((e) => e.refId).toList()}, + ); + } +} + +extension RefList_Batch on List { + /// 为类型添加属性 + Future addProperty_batch(int propertyKey, List property) async { + assert(property is List); + return kMethodChannel.invokeMethod( + 'PlatformService::addProperty_batch', + [ + for (int i = 0; i < length; i++) + { + '__this__': this[i], + 'propertyKey': propertyKey, + 'property': property[i], + } + ], + ); + } + + /// 获取添加字段的值 + Future> getProperty_batch(int propertyKey) async { + final List resultBatch = await kMethodChannel.invokeMethod( + 'PlatformService::getProperty_batch', + [ + for (int i = 0; i < length; i++) + { + '__this__': this[i], + 'propertyKey': propertyKey, + } + ], + ); + return resultBatch + .map((refId) => Ref() + ..refId = refId + ..tag__ = 'platform') + .toList(); + } + + /// 为类型添加jsonable属性 + Future addJsonableProperty_batch( + int propertyKey, + List property, + ) async { + assert(property is List || + property is List || + property is List || + property is List || + property is List || + property is List); + return kMethodChannel.invokeMethod( + 'PlatformService::addJsonableProperty_batch', + [ + for (int i = 0; i < length; i++) + { + '__this__': this[i], + 'propertyKey': propertyKey, + 'property': property[i], + } + ], + ); + } + + /// 获取添加字段的jsonable值 + Future> getJsonableProperty_batch(int propertyKey) async { + final List resultBatch = await kMethodChannel.invokeMethod( + 'PlatformService::getJsonableProperty_batch', + [ + for (int i = 0; i < length; i++) + { + '__this__': this[i], + 'propertyKey': propertyKey, + } + ], + ); + return resultBatch; + } +} diff --git a/lib/src/type/core/stack.dart b/lib/src/type/core/stack.dart new file mode 100644 index 0000000..77f6b8c --- /dev/null +++ b/lib/src/type/core/stack.dart @@ -0,0 +1,34 @@ +import 'dart:collection'; + +class Stack { + final ListQueue _list = ListQueue(); + + /// check if the stack is empty. + bool get isEmpty => _list.isEmpty; + + /// check if the stack is not empty. + bool get isNotEmpty => _list.isNotEmpty; + + /// push element in top of the stack. + void push(T e) { + _list.addLast(e); + } + + /// get the top of the stack and delete it. + T pop() { + T res = _list.last; + _list.removeLast(); + return res; + } + + /// get the top of the stack without deleting it. + T? peek() { + if (_list.isEmpty) return null; + return _list.last; + } + + /// get the size of the stack. + int size() { + return _list.length; + } +} diff --git a/lib/src/type/core/typedefs.dart b/lib/src/type/core/typedefs.dart new file mode 100644 index 0000000..54d2cf7 --- /dev/null +++ b/lib/src/type/core/typedefs.dart @@ -0,0 +1,181 @@ +import 'dart:async'; + +import 'package:foundation_fluttify/foundation_fluttify.dart'; +import 'package:foundation_fluttify/src/type/platform/ios_type/ui_application.dart'; + +typedef FutureVoidCallback = Future Function(); +typedef FutureValueChanged = Future Function(T value); +typedef Action0 = FutureOr Function(); +typedef Action1 = FutureOr Function(T arg0); +typedef Action2 = FutureOr Function(T1 arg0, T2 arg1); +typedef Action3 = FutureOr Function( + T1 arg1, T2 arg2, T3 arg3); +typedef Action4 = FutureOr Function( + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, +); +typedef Action5 = FutureOr Function( + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, +); +typedef Action6 = FutureOr Function( + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, +); +typedef Action7 = FutureOr Function( + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, +); +typedef Action8 = FutureOr Function( + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, +); +typedef Action9 = FutureOr Function( + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, +); +typedef Function0 = FutureOr Function(); +typedef Function1 = FutureOr Function(T arg0); +typedef Function2 = FutureOr Function(T1 arg0, T2 arg1); +typedef Function3 = FutureOr Function( + T1 arg1, T2 arg2, T3 arg3); +typedef Function4 = FutureOr Function( + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, +); +typedef Function5 = FutureOr Function( + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, +); +typedef Function6 = FutureOr Function( + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, +); +typedef Function7 = FutureOr Function( + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, +); +typedef Function8 = FutureOr Function( + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, +); +typedef Function9 = FutureOr Function( + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, +); + +typedef ApplicationDidFinishLaunchingWithOptions = void Function( + UIApplication application, + Map options, +); +typedef ApplicationWillFinishLaunchingWithOptions = void Function( + UIApplication application, + Map options, +); +typedef ApplicationDidBecomeActive = void Function(UIApplication application); +typedef ApplicationWillResignActive = void Function(UIApplication application); +typedef ApplicationDidEnterBackground = void Function( + UIApplication application); +typedef ApplicationWillEnterForeground = void Function( + UIApplication application); +typedef ApplicationWillTerminate = void Function(UIApplication application); +typedef ApplicationDidRegisterUserNotificationSettings = void Function( + UIApplication application, + UIUserNotificationSettings notificationSettings, +); +typedef ApplicationDidRegisterForRemoteNotificationsWithDeviceToken = void + Function( + UIApplication application, + NSData deviceToken, +); +typedef ApplicationDidReceiveRemoteNotificationFetchCompletionHandler = void + Function( + UIApplication application, + Map userInfo, +); +typedef ApplicationOpenURLOptions = void Function( + UIApplication application, + NSURL url, + Map options, +); +typedef ApplicationHandleOpenURL = void Function( + UIApplication application, + NSURL url, +); +typedef ApplicationOpenURLSourceApplicationAnnotation = void Function( + UIApplication application, + NSURL url, + String sourceApplication, + NSObject annotation, +); +typedef ApplicationPerformActionForShortcutItemCompletionHandler = void + Function( + UIApplication application, + UIApplicationShortcutItem shortcutItem, +); +typedef ApplicationHandleEventsForBackgroundURLSessionCompletionHandler = void + Function( + UIApplication application, + String identifier, +); +typedef ApplicationPerformFetchWithCompletionHandler = void Function( + UIApplication application, +); +typedef ApplicationContinueUserActivityRestorationHandler = void Function( + UIApplication application, + NSUserActivity userActivity, +); diff --git a/lib/src/type/platform/android_type/android/app/activity.dart b/lib/src/type/platform/android_type/android/app/activity.dart new file mode 100644 index 0000000..f044e9e --- /dev/null +++ b/lib/src/type/platform/android_type/android/app/activity.dart @@ -0,0 +1,22 @@ +import 'package:foundation_fluttify/foundation_fluttify.dart'; +import 'package:foundation_fluttify/src/object/obejcts.dart'; +import 'package:foundation_fluttify/src/type/platform/android_type/android/content/context.dart'; +import 'package:foundation_fluttify/src/type/platform/android_type/android/content/intent.dart'; + +// ignore_for_file: non_constant_identifier_names, camel_case_types, missing_return, unused_import +class android_app_Activity extends android_content_Context { + @override + final String tag__ = 'platform'; + + static Future get() async { + final result = + await kMethodChannel.invokeMethod('android.app.Activity::get'); + return android_app_Activity()..refId = result?.refId; + } + + Future get intent async { + final result = await kMethodChannel.invokeMethod( + 'android.app.Activity::getIntent', {'__this__': this}); + return android_content_Intent()..refId = result?.refId; + } +} diff --git a/lib/src/type/platform/android_type/android/app/application.dart b/lib/src/type/platform/android_type/android/app/application.dart new file mode 100644 index 0000000..c63ed6d --- /dev/null +++ b/lib/src/type/platform/android_type/android/app/application.dart @@ -0,0 +1,15 @@ +import 'package:foundation_fluttify/foundation_fluttify.dart'; +import 'package:foundation_fluttify/src/object/obejcts.dart'; +import 'package:foundation_fluttify/src/type/platform/android_type/android/content/context.dart'; + +// ignore_for_file: non_constant_identifier_names, camel_case_types, missing_return, unused_import +class android_app_Application extends android_content_Context { + @override + final String tag__ = 'platform'; + + static Future get() async { + final result = + await kMethodChannel.invokeMethod('android.app.Application::get'); + return android_app_Application()..refId = result?.refId; + } +} diff --git a/lib/src/type/platform/android_type/android/app/notification.dart b/lib/src/type/platform/android_type/android/app/notification.dart new file mode 100644 index 0000000..4dceda7 --- /dev/null +++ b/lib/src/type/platform/android_type/android/app/notification.dart @@ -0,0 +1,35 @@ +import 'package:flutter/cupertino.dart'; +import 'package:foundation_fluttify/foundation_fluttify.dart'; +import 'package:foundation_fluttify/src/object/obejcts.dart'; +import 'package:foundation_fluttify/src/type/platform/android_type/android/content/context.dart'; +import 'package:foundation_fluttify/src/type/platform/android_type/android/content/intent.dart'; + +// ignore_for_file: non_constant_identifier_names, camel_case_types, missing_return, unused_import +class android_app_Notification extends java_lang_Object { + @override + final String tag__ = 'platform'; + + static Future create({ + required String contentTitle, + required String contentText, + int? when, + required String channelId, + required String channelName, + bool enableLights = true, + bool showBadge = true, + }) async { + final result = await kMethodChannel.invokeMethod( + 'android.app.Notification::create', + { + 'contentTitle': contentTitle, + 'contentText': contentText, + 'when': when ?? DateTime.now().millisecondsSinceEpoch, + 'channelId': channelId, + 'channelName': channelName, + 'enableLights': enableLights, + 'showBadge': showBadge, + }, + ); + return android_app_Notification()..refId = result?.refId; + } +} diff --git a/lib/src/type/platform/android_type/android/app/pending_intent.dart b/lib/src/type/platform/android_type/android/app/pending_intent.dart new file mode 100644 index 0000000..c62a8b6 --- /dev/null +++ b/lib/src/type/platform/android_type/android/app/pending_intent.dart @@ -0,0 +1,11 @@ +import 'package:foundation_fluttify/foundation_fluttify.dart'; +import 'package:foundation_fluttify/src/object/obejcts.dart'; +import 'package:foundation_fluttify/src/type/platform/android_type/android/content/context.dart'; +import 'package:foundation_fluttify/src/type/platform/android_type/android/content/intent.dart'; + +// ignore_for_file: non_constant_identifier_names, camel_case_types, missing_return, unused_import +class android_app_PendingIntent extends java_lang_Object + with android_os_Parcelable { + @override + final String tag__ = 'platform'; +} diff --git a/lib/src/type/platform/android_type/android/content/broadcast_receiver.dart b/lib/src/type/platform/android_type/android/content/broadcast_receiver.dart new file mode 100644 index 0000000..b12a229 --- /dev/null +++ b/lib/src/type/platform/android_type/android/content/broadcast_receiver.dart @@ -0,0 +1,37 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/services.dart'; +import 'package:foundation_fluttify/foundation_fluttify.dart'; +import 'package:foundation_fluttify/src/object/obejcts.dart'; +import 'package:foundation_fluttify/src/type/platform/android_type/java/lang/object.dart'; + +import 'intent.dart'; + +// ignore_for_file: non_constant_identifier_names, camel_case_types, missing_return, unused_import +class android_content_BroadcastReceiver extends java_lang_Object { + @override + final String tag__ = 'platform'; + + Future create( + ValueChanged onReceive, + ) async { + final result = await kMethodChannel.invokeMethod( + 'android.content.Context::registerReceiver', + { + '__this__': this, + 'broadcastReceiver': '', + 'intentFilter': '', + }, + ); + + MethodChannel('android.content.BroadcastReceiver::create::Callback') + .setMethodCallHandler((call) async { + if (call.method == + 'Callback::android.content.BroadcastReceiver::onReceive') { + final intentRefId = call.arguments['intent'] as String; + final intent = android_content_Intent()..refId = intentRefId; + onReceive(intent); + } + }); + return android_content_BroadcastReceiver()..refId = result?.refId; + } +} diff --git a/lib/src/type/platform/android_type/android/content/content_provider.dart b/lib/src/type/platform/android_type/android/content/content_provider.dart new file mode 100644 index 0000000..a324d0f --- /dev/null +++ b/lib/src/type/platform/android_type/android/content/content_provider.dart @@ -0,0 +1,9 @@ + + +import 'package:foundation_fluttify/src/type/platform/android_type/java/lang/object.dart'; + +// ignore_for_file: non_constant_identifier_names, camel_case_types, missing_return, unused_import +class android_content_ContentProvider extends java_lang_Object { + @override + final String tag__ = 'platform'; +} diff --git a/lib/src/type/platform/android_type/android/content/context.dart b/lib/src/type/platform/android_type/android/content/context.dart new file mode 100644 index 0000000..55e616f --- /dev/null +++ b/lib/src/type/platform/android_type/android/content/context.dart @@ -0,0 +1,28 @@ +import 'package:foundation_fluttify/foundation_fluttify.dart'; +import 'package:foundation_fluttify/src/object/obejcts.dart'; +import 'package:foundation_fluttify/src/type/platform/android_type/java/lang/object.dart'; + +import 'broadcast_receiver.dart'; +import 'intent.dart'; +import 'intent_filter.dart'; + +// ignore_for_file: non_constant_identifier_names, camel_case_types, missing_return, unused_import +class android_content_Context extends java_lang_Object { + @override + final String tag__ = 'platform'; + + Future registerReceiver( + android_content_BroadcastReceiver receiver, + android_content_IntentFilter intentFilter, + ) async { + final result = await kMethodChannel.invokeMethod( + 'android.content.Context::registerReceiver', + { + '__this__': this, + 'broadcastReceiver': receiver, + 'intentFilter': intentFilter, + }, + ); + return android_content_Intent()..refId = result?.refId; + } +} diff --git a/lib/src/type/platform/android_type/android/content/intent.dart b/lib/src/type/platform/android_type/android/content/intent.dart new file mode 100644 index 0000000..ca67dc7 --- /dev/null +++ b/lib/src/type/platform/android_type/android/content/intent.dart @@ -0,0 +1,23 @@ + + +import 'package:foundation_fluttify/src/object/obejcts.dart'; +import 'package:foundation_fluttify/src/type/platform/android_type/android/os/bundle.dart'; +import 'package:foundation_fluttify/src/type/platform/android_type/java/lang/object.dart'; + +// ignore_for_file: non_constant_identifier_names, camel_case_types, missing_return, unused_import +class android_content_Intent extends java_lang_Object { + @override + final String tag__ = 'platform'; + + Future?> get bundle async { + final result = await kMethodChannel.invokeMapMethod( + 'android.content.Intent::getBundle', {'__this__': this}); + return result; + } + + Future get action async { + final result = await kMethodChannel + .invokeMethod('android.content.Intent::getAction', {'__this__': this}); + return result; + } +} diff --git a/lib/src/type/platform/android_type/android/content/intent_filter.dart b/lib/src/type/platform/android_type/android/content/intent_filter.dart new file mode 100644 index 0000000..d3bb0a4 --- /dev/null +++ b/lib/src/type/platform/android_type/android/content/intent_filter.dart @@ -0,0 +1,19 @@ +import 'package:foundation_fluttify/foundation_fluttify.dart'; +import 'package:foundation_fluttify/src/object/obejcts.dart'; +import 'package:foundation_fluttify/src/type/platform/android_type/java/lang/object.dart'; + +import 'intent.dart'; + +// ignore_for_file: non_constant_identifier_names, camel_case_types, missing_return, unused_import +class android_content_IntentFilter extends java_lang_Object { + @override + final String tag__ = 'platform'; + + Future create(String action) async { + final result = await kMethodChannel.invokeMethod( + 'android.content.IntentFilter::create', + {'__this__': this, 'action': action}, + ); + return android_content_IntentFilter()..refId = result?.refId; + } +} diff --git a/lib/src/type/platform/android_type/android/graphics/bitmap.dart b/lib/src/type/platform/android_type/android/graphics/bitmap.dart new file mode 100644 index 0000000..c57f277 --- /dev/null +++ b/lib/src/type/platform/android_type/android/graphics/bitmap.dart @@ -0,0 +1,57 @@ +// ignore_for_file: non_constant_identifier_names, camel_case_types, missing_return, unused_import + +import 'dart:typed_data'; + +import 'package:foundation_fluttify/foundation_fluttify.dart'; +import 'package:foundation_fluttify/src/object/obejcts.dart'; +import 'package:foundation_fluttify/src/type/platform/android_type/java/lang/object.dart'; + +class android_graphics_Bitmap extends java_lang_Object { + @override + final String tag__ = 'platform'; + + static Future create(Uint8List bitmapBytes) async { + final result = await kMethodChannel.invokeMethod( + 'android.graphics.Bitmap::create', {'bitmapBytes': bitmapBytes}); + return android_graphics_Bitmap()..refId = result?.refId; + } + + static Future createWithDrawable( + String drawableId, + ) async { + final result = await kMethodChannel.invokeMethod( + 'android.graphics.Bitmap::createWithDrawable', + {'drawableId': drawableId}, + ); + return android_graphics_Bitmap()..refId = result?.refId; + } + + static Future?> create_batch( + List bitmapBytesBatch, + ) async { + final resultBatch = await kMethodChannel.invokeListMethod( + 'android.graphics.Bitmap::create_batch', + [ + for (final bitmapBytes in bitmapBytesBatch) {'bitmapBytes': bitmapBytes} + ], + ); + return resultBatch + ?.map((it) => android_graphics_Bitmap()..refId = it.refId) + .toList(); + } + + Future get data { + return kMethodChannel + .invokeMethod('android.graphics.Bitmap::getData', {'__this__': this}); + } + + Future recycle() { + return kMethodChannel + .invokeMethod('android.graphics.Bitmap::recycle', {'__this__': this}); + } + + Future get isRecycled { + return kMethodChannel.invokeMethod( + 'android.graphics.Bitmap::isRecycled', {'__this__': this}); + } +} diff --git a/lib/src/type/platform/android_type/android/graphics/drawable/drawable.dart b/lib/src/type/platform/android_type/android/graphics/drawable/drawable.dart new file mode 100644 index 0000000..00ffe4a --- /dev/null +++ b/lib/src/type/platform/android_type/android/graphics/drawable/drawable.dart @@ -0,0 +1,7 @@ +// ignore_for_file: non_constant_identifier_names, camel_case_types, missing_return, unused_import +import 'package:foundation_fluttify/src/type/platform/android_type/java/lang/object.dart'; + +class android_graphics_drawable_Drawable extends java_lang_Object { + @override + final String tag__ = 'platform'; +} diff --git a/lib/src/type/platform/android_type/android/graphics/point.dart b/lib/src/type/platform/android_type/android/graphics/point.dart new file mode 100644 index 0000000..4b9bad9 --- /dev/null +++ b/lib/src/type/platform/android_type/android/graphics/point.dart @@ -0,0 +1,28 @@ +// ignore_for_file: non_constant_identifier_names, camel_case_types, missing_return, unused_import + +import 'dart:typed_data'; + +import 'package:foundation_fluttify/foundation_fluttify.dart'; +import 'package:foundation_fluttify/src/object/obejcts.dart'; +import 'package:foundation_fluttify/src/type/platform/android_type/java/lang/object.dart'; + +class android_graphics_Point extends java_lang_Object { + @override + final String tag__ = 'platform'; + + static Future create(int x, int y) async { + final result = await kMethodChannel + .invokeMethod('android.graphics.Point::create', {'x': x, 'y': y}); + return android_graphics_Point()..refId = result?.refId; + } + + Future get x { + return kMethodChannel + .invokeMethod('android.graphics.Point::getX', {'__this__': this}); + } + + Future get y { + return kMethodChannel + .invokeMethod('android.graphics.Point::getY', {'__this__': this}); + } +} diff --git a/lib/src/type/platform/android_type/android/graphics/point_f.dart b/lib/src/type/platform/android_type/android/graphics/point_f.dart new file mode 100644 index 0000000..838f456 --- /dev/null +++ b/lib/src/type/platform/android_type/android/graphics/point_f.dart @@ -0,0 +1,7 @@ +// ignore_for_file: non_constant_identifier_names, camel_case_types, missing_return, unused_import +import 'package:foundation_fluttify/src/type/platform/android_type/java/lang/object.dart'; + +class android_graphics_PointF extends java_lang_Object { + @override + final String tag__ = 'platform'; +} diff --git a/lib/src/type/platform/android_type/android/location/location.dart b/lib/src/type/platform/android_type/android/location/location.dart new file mode 100644 index 0000000..5fb3075 --- /dev/null +++ b/lib/src/type/platform/android_type/android/location/location.dart @@ -0,0 +1,88 @@ +// ignore_for_file: non_constant_identifier_names, camel_case_types, missing_return, unused_import + +import 'package:foundation_fluttify/foundation_fluttify.dart'; +import 'package:foundation_fluttify/src/object/obejcts.dart'; +import 'package:foundation_fluttify/src/type/platform/android_type/java/lang/object.dart'; + +class android_location_Location extends java_lang_Object { + static Future create(String provider) async { + final result = await kMethodChannel.invokeMethod( + 'android.location.Location::create', {'provider': provider}); + return android_location_Location()..refId = result?.refId; + } + + @override + final String tag__ = 'platform'; + + Future get latitude { + return kMethodChannel.invokeMethod( + 'android.location.Location::getLatitude', {'__this__': this}); + } + + Future get longitude { + return kMethodChannel.invokeMethod( + 'android.location.Location::getLongitude', {'__this__': this}); + } + + Future get bearing { + return kMethodChannel.invokeMethod( + 'android.location.Location::getBearing', {'__this__': this}); + } + + Future get altitude { + return kMethodChannel.invokeMethod( + 'android.location.Location::getAltitude', {'__this__': this}); + } + + Future get accuracy { + return kMethodChannel.invokeMethod( + 'android.location.Location::getAccuracy', {'__this__': this}); + } + + Future get speed { + return kMethodChannel.invokeMethod( + 'android.location.Location::getSpeed', {'__this__': this}); + } + + Future setLatitude(double latitude) async { + return kMethodChannel.invokeMethod( + 'android.location.Location::setLatitude', + {'__this__': this, 'latitude': latitude}, + ); + } + + Future setLongitude(double longitude) async { + return kMethodChannel.invokeMethod( + 'android.location.Location::setLongitude', + {'__this__': this, 'longitude': longitude}, + ); + } + + Future setBearing(double bearing) async { + return kMethodChannel.invokeMethod( + 'android.location.Location::setBearing', + {'__this__': this, 'bearing': bearing}, + ); + } + + Future setAltitude(double altitude) async { + return kMethodChannel.invokeMethod( + 'android.location.Location::setAltitude', + {'__this__': this, 'altitude': altitude}, + ); + } + + Future setAccuracy(double accuracy) async { + return kMethodChannel.invokeMethod( + 'android.location.Location::setAccuracy', + {'__this__': this, 'accuracy': accuracy}, + ); + } + + Future setSpeed(double speed) async { + return kMethodChannel.invokeMethod( + 'android.location.Location::setSpeed', + {'__this__': this, 'speed': speed}, + ); + } +} diff --git a/lib/src/type/platform/android_type/android/opengl/gl_surface_view.dart b/lib/src/type/platform/android_type/android/opengl/gl_surface_view.dart new file mode 100644 index 0000000..1acfcfb --- /dev/null +++ b/lib/src/type/platform/android_type/android/opengl/gl_surface_view.dart @@ -0,0 +1,6 @@ +import 'package:foundation_fluttify/foundation_fluttify.dart'; + +class android_opengl_GLSurfaceView extends android_view_SurfaceView { + @override + final String tag__ = 'platform'; +} diff --git a/lib/src/type/platform/android_type/android/os/binder.dart b/lib/src/type/platform/android_type/android/os/binder.dart new file mode 100644 index 0000000..86e4f0f --- /dev/null +++ b/lib/src/type/platform/android_type/android/os/binder.dart @@ -0,0 +1,7 @@ +// ignore_for_file: non_constant_identifier_names, camel_case_types, missing_return, unused_import +import 'package:foundation_fluttify/src/type/platform/android_type/java/lang/object.dart'; + +class android_os_Binder extends java_lang_Object { + @override + final String tag__ = 'platform'; +} diff --git a/lib/src/type/platform/android_type/android/os/bundle.dart b/lib/src/type/platform/android_type/android/os/bundle.dart new file mode 100644 index 0000000..adcbd25 --- /dev/null +++ b/lib/src/type/platform/android_type/android/os/bundle.dart @@ -0,0 +1,59 @@ +import 'package:foundation_fluttify/foundation_fluttify.dart'; +import 'package:foundation_fluttify/src/object/obejcts.dart'; +import 'package:foundation_fluttify/src/type/platform/android_type/java/lang/object.dart'; + +// ignore_for_file: non_constant_identifier_names, camel_case_types, missing_return, unused_import +class android_os_Bundle extends java_lang_Object { + static Future create() async { + final result = + await kMethodChannel.invokeMethod('android.os.Bundle::create'); + return android_os_Bundle()..refId = result?.refId; + } + + @override + final String tag__ = 'platform'; + + Future putString(String key, String value) { + return kMethodChannel.invokeMethod('android.os.Bundle::putString', { + '__this__': this, + 'key': key, + 'value': value, + }); + } + + Future putInt(String key, int value) { + return kMethodChannel.invokeMethod('android.os.Bundle::putInt', { + '__this__': this, + 'key': key, + 'value': value, + }); + } + + Future getString(String key) { + return kMethodChannel.invokeMethod( + 'android.os.Bundle::getString', + {'__this__': this, 'key': key}, + ); + } + + Future getInt(String key) { + return kMethodChannel.invokeMethod( + 'android.os.Bundle::getInt', + {'__this__': this, 'key': key}, + ); + } + + Future getDouble(String key) { + return kMethodChannel.invokeMethod( + 'android.os.Bundle::getDouble', + {'__this__': this, 'key': key}, + ); + } + + Future getFloat(String key) { + return kMethodChannel.invokeMethod( + 'android.os.Bundle::getFloat', + {'__this__': this, 'key': key}, + ); + } +} diff --git a/lib/src/type/platform/android_type/android/os/parcelable.dart b/lib/src/type/platform/android_type/android/os/parcelable.dart new file mode 100644 index 0000000..c54c286 --- /dev/null +++ b/lib/src/type/platform/android_type/android/os/parcelable.dart @@ -0,0 +1,14 @@ +// ignore_for_file: non_constant_identifier_names, camel_case_types, missing_return, unused_import +import 'package:foundation_fluttify/src/type/platform/android_type/java/lang/object.dart'; + +class _android_os_Parcelable_SUB extends java_lang_Object + with android_os_Parcelable {} + +mixin android_os_Parcelable on java_lang_Object { + @override + final String tag__ = 'platform'; + + static android_os_Parcelable subInstance() { + return _android_os_Parcelable_SUB(); + } +} diff --git a/lib/src/type/platform/android_type/android/util/pair.dart b/lib/src/type/platform/android_type/android/util/pair.dart new file mode 100644 index 0000000..6f18c53 --- /dev/null +++ b/lib/src/type/platform/android_type/android/util/pair.dart @@ -0,0 +1,21 @@ +// ignore_for_file: non_constant_identifier_names, camel_case_types, missing_return, unused_import + + + +import 'package:foundation_fluttify/src/object/obejcts.dart'; +import 'package:foundation_fluttify/src/type/platform/android_type/java/lang/object.dart'; + +class android_util_Pair extends java_lang_Object { + @override + final String tag__ = 'platform'; + + Future get first { + return kMethodChannel + .invokeMethod('android.util.Pair::getFirst', {'__this__': this}); + } + + Future get second { + return kMethodChannel + .invokeMethod('android.util.Pair::getSecond', {'__this__': this}); + } +} diff --git a/lib/src/type/platform/android_type/android/view/motion_event.dart b/lib/src/type/platform/android_type/android/view/motion_event.dart new file mode 100644 index 0000000..45623a6 --- /dev/null +++ b/lib/src/type/platform/android_type/android/view/motion_event.dart @@ -0,0 +1,7 @@ +// ignore_for_file: non_constant_identifier_names, camel_case_types, missing_return, unused_import +import 'package:foundation_fluttify/src/type/platform/android_type/java/lang/object.dart'; + +class android_view_MotionEvent extends java_lang_Object { + @override + final String tag__ = 'platform'; +} diff --git a/lib/src/type/platform/android_type/android/view/surface_holder.dart b/lib/src/type/platform/android_type/android/view/surface_holder.dart new file mode 100644 index 0000000..f9e670c --- /dev/null +++ b/lib/src/type/platform/android_type/android/view/surface_holder.dart @@ -0,0 +1,71 @@ +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; +import 'package:foundation_fluttify/foundation_fluttify.dart'; + +class _android_view_SurfaceHolder_SUB extends java_lang_Object + with android_view_SurfaceHolder {} + +mixin android_view_SurfaceHolder on java_lang_Object { + static android_view_SurfaceHolder subInstance() => + _android_view_SurfaceHolder_SUB(); + + @override + final String tag__ = 'platform'; + + Future addCallback( + android_view_SurfaceHolder_Callback callback, + ) async { + // invoke native method + await kMethodChannel.invokeMethod( + 'android.view.SurfaceHolder::addCallback', + {'__this__': this, 'callback': callback}, + ); + + // handle native call + MethodChannel( + 'android.view.SurfaceHolder::addCallback::Callback', + kMethodCodec, + ).setMethodCallHandler((methodCall) async { + try { + final args = methodCall.arguments as Map?; + switch (methodCall.method) { + case 'Callback::android.view.SurfaceHolder.Callback::surfaceCreated': + callback.surfaceCreated(args!['var1']); + break; + case 'Callback::android.view.SurfaceHolder.Callback::surfaceChanged': + callback.surfaceChanged( + args!['var1'], + args['var2'], + args['var3'], + args['var4'], + ); + break; + case 'Callback::android.view.SurfaceHolder.Callback::surfaceDestroyed': + callback.surfaceDestroyed(args!['var1']); + break; + default: + throw MissingPluginException('方法${methodCall.method}未实现'); + } + } catch (e) { + debugPrint(e.toString()); + rethrow; + } + }); + } +} + +mixin android_view_SurfaceHolder_Callback on java_lang_Object { + @override + final String tag__ = 'platform'; + + void surfaceCreated(android_view_SurfaceHolder? var1) {} + + void surfaceChanged( + android_view_SurfaceHolder? var1, + int? var2, + int? var3, + int? var4, + ) {} + + void surfaceDestroyed(android_view_SurfaceHolder? var1) {} +} diff --git a/lib/src/type/platform/android_type/android/view/surface_view.dart b/lib/src/type/platform/android_type/android/view/surface_view.dart new file mode 100644 index 0000000..9343aba --- /dev/null +++ b/lib/src/type/platform/android_type/android/view/surface_view.dart @@ -0,0 +1,28 @@ +import 'package:foundation_fluttify/foundation_fluttify.dart'; + +class android_view_SurfaceView extends android_view_View { + @override + final String tag__ = 'platform'; + + Future getHolder() async { + final result = await kMethodChannel.invokeMethod( + 'android.view.SurfaceView::getHolder', + {'__this__': this}, + ); + return android_view_SurfaceHolder.subInstance()..refId = result?.refId; + } + + Future setZOrderOnTop(bool onTop) async { + await kMethodChannel.invokeMethod( + 'android.view.SurfaceView::setZOrderOnTop', + {'__this__': this, 'onTop': onTop}, + ); + } + + Future setZOrderMediaOverlay(bool isMediaOverlay) async { + await kMethodChannel.invokeMethod( + 'android.view.SurfaceView::setZOrderMediaOverlay', + {'__this__': this, 'isMediaOverlay': isMediaOverlay}, + ); + } +} diff --git a/lib/src/type/platform/android_type/android/view/view.dart b/lib/src/type/platform/android_type/android/view/view.dart new file mode 100644 index 0000000..e880bbf --- /dev/null +++ b/lib/src/type/platform/android_type/android/view/view.dart @@ -0,0 +1,42 @@ +// ignore_for_file: non_constant_identifier_names, camel_case_types, missing_return, unused_import +import 'package:foundation_fluttify/src/object/obejcts.dart'; +import 'package:foundation_fluttify/src/type/platform/android_type/java/lang/object.dart'; + +class android_view_View extends java_lang_Object { + @override + final String tag__ = 'platform'; +} + +class _android_view_View_OnApplyWindowInsetsListener_SUB + extends java_lang_Object + with android_view_View_OnApplyWindowInsetsListener { + @override + final String tag__ = 'platform'; +} + +mixin android_view_View_OnApplyWindowInsetsListener on java_lang_Object { + static android_view_View_OnApplyWindowInsetsListener subInstance() => + _android_view_View_OnApplyWindowInsetsListener_SUB(); + @override + final String tag__ = 'platform'; +} + +class _android_view_View_OnClickListener_SUB extends java_lang_Object + with android_view_View_OnClickListener {} + +mixin android_view_View_OnClickListener on java_lang_Object { + static android_view_View_OnClickListener subInstance() => + _android_view_View_OnClickListener_SUB(); + @override + final String tag__ = 'platform'; +} + +class _android_view_View_OnTouchListener_SUB extends java_lang_Object + with android_view_View_OnTouchListener {} + +mixin android_view_View_OnTouchListener on java_lang_Object { + static android_view_View_OnTouchListener subInstance() => + _android_view_View_OnTouchListener_SUB(); + @override + final String tag__ = 'platform'; +} diff --git a/lib/src/type/platform/android_type/android/view/view_group.dart b/lib/src/type/platform/android_type/android/view/view_group.dart new file mode 100644 index 0000000..b3980f4 --- /dev/null +++ b/lib/src/type/platform/android_type/android/view/view_group.dart @@ -0,0 +1,22 @@ +// ignore_for_file: non_constant_identifier_names, camel_case_types, missing_return, unused_import +import 'package:foundation_fluttify/src/object/obejcts.dart'; +import 'package:foundation_fluttify/src/type/platform/android_type/android/view/view.dart'; + +class android_view_ViewGroup extends android_view_View { + @override + final String tag__ = 'platform'; + + Future addView(android_view_View child) { + return kMethodChannel.invokeMethod( + 'android.view.ViewGroup::addView', + {'__this__': this, 'child': child}, + ); + } + + Future removeAllViews() { + return kMethodChannel.invokeMethod( + 'android.view.ViewGroup::removeAllViews', + {'__this__': this}, + ); + } +} diff --git a/lib/src/type/platform/android_type/android/widget/frame_layout.dart b/lib/src/type/platform/android_type/android/widget/frame_layout.dart new file mode 100644 index 0000000..51575f8 --- /dev/null +++ b/lib/src/type/platform/android_type/android/widget/frame_layout.dart @@ -0,0 +1,7 @@ +// ignore_for_file: non_constant_identifier_names, camel_case_types, missing_return, unused_import +import 'package:foundation_fluttify/src/type/platform/android_type/android/view/view_group.dart'; + +class android_widget_FrameLayout extends android_view_ViewGroup { + @override + final String tag__ = 'platform'; +} diff --git a/lib/src/type/platform/android_type/android/widget/image_view.dart b/lib/src/type/platform/android_type/android/widget/image_view.dart new file mode 100644 index 0000000..f8d50f8 --- /dev/null +++ b/lib/src/type/platform/android_type/android/widget/image_view.dart @@ -0,0 +1,18 @@ +// ignore_for_file: non_constant_identifier_names, camel_case_types, missing_return, unused_import +import 'package:foundation_fluttify/foundation_fluttify.dart'; +import 'package:foundation_fluttify/src/type/platform/android_type/android/view/view.dart'; + +class android_widget_ImageView extends android_view_View { + @override + final String tag__ = 'platform'; + + static Future createWithBitmap( + android_graphics_Bitmap bitmap, + ) async { + final result = await kMethodChannel.invokeMethod( + 'android.widget.ImageView::createWithBitmap', + {'bitmap': bitmap}, + ); + return android_widget_ImageView()..refId = result?.refId; + } +} diff --git a/lib/src/type/platform/android_type/android/widget/linear_layout.dart b/lib/src/type/platform/android_type/android/widget/linear_layout.dart new file mode 100644 index 0000000..b8fa853 --- /dev/null +++ b/lib/src/type/platform/android_type/android/widget/linear_layout.dart @@ -0,0 +1,7 @@ +// ignore_for_file: non_constant_identifier_names, camel_case_types, missing_return, unused_import +import 'package:foundation_fluttify/src/type/platform/android_type/android/view/view_group.dart'; + +class android_widget_LinearLayout extends android_view_ViewGroup { + @override + final String tag__ = 'platform'; +} diff --git a/lib/src/type/platform/android_type/android/widget/relative_layout.dart b/lib/src/type/platform/android_type/android/widget/relative_layout.dart new file mode 100644 index 0000000..1ec0828 --- /dev/null +++ b/lib/src/type/platform/android_type/android/widget/relative_layout.dart @@ -0,0 +1,7 @@ +// ignore_for_file: non_constant_identifier_names, camel_case_types, missing_return, unused_import +import 'package:foundation_fluttify/src/type/platform/android_type/android/view/view_group.dart'; + +class android_widget_RelativeLayout extends android_view_ViewGroup { + @override + final String tag__ = 'platform'; +} diff --git a/lib/src/type/platform/android_type/android/widget/text_view.dart b/lib/src/type/platform/android_type/android/widget/text_view.dart new file mode 100644 index 0000000..2439f7b --- /dev/null +++ b/lib/src/type/platform/android_type/android/widget/text_view.dart @@ -0,0 +1,7 @@ +// ignore_for_file: non_constant_identifier_names, camel_case_types, missing_return, unused_import +import 'package:foundation_fluttify/src/type/platform/android_type/android/view/view.dart'; + +class android_widget_TextView extends android_view_View { + @override + final String tag__ = 'platform'; +} diff --git a/lib/src/type/platform/android_type/java/io/closeable.dart b/lib/src/type/platform/android_type/java/io/closeable.dart new file mode 100644 index 0000000..8758bd2 --- /dev/null +++ b/lib/src/type/platform/android_type/java/io/closeable.dart @@ -0,0 +1,16 @@ +import 'package:foundation_fluttify/foundation_fluttify.dart'; + +// ignore_for_file: non_constant_identifier_names, camel_case_types, missing_return, unused_import +class _java_io_Closeable_SUB extends java_lang_Object with java_io_Closeable { + @override + final String tag__ = 'platform'; +} + +mixin java_io_Closeable on java_lang_Object { + static java_io_Closeable subInstance() { + return _java_io_Closeable_SUB(); + } + + @override + final String tag__ = 'platform'; +} diff --git a/lib/src/type/platform/android_type/java/io/file.dart b/lib/src/type/platform/android_type/java/io/file.dart new file mode 100644 index 0000000..d757204 --- /dev/null +++ b/lib/src/type/platform/android_type/java/io/file.dart @@ -0,0 +1,13 @@ +import 'package:foundation_fluttify/foundation_fluttify.dart'; + +// ignore_for_file: non_constant_identifier_names, camel_case_types, missing_return, unused_import +class java_io_File extends java_lang_Object { + @override + final String tag__ = 'platform'; + + static Future create(String path) async { + final result = await kMethodChannel + .invokeMethod('java.io.File::create', {'path': path}); + return java_io_File()..refId = result?.refId; + } +} diff --git a/lib/src/type/platform/android_type/java/io/serializable.dart b/lib/src/type/platform/android_type/java/io/serializable.dart new file mode 100644 index 0000000..8cfa3d8 --- /dev/null +++ b/lib/src/type/platform/android_type/java/io/serializable.dart @@ -0,0 +1,17 @@ +import 'package:foundation_fluttify/foundation_fluttify.dart'; + +// ignore_for_file: non_constant_identifier_names, camel_case_types, missing_return, unused_import +class _java_io_Serializable_SUB extends java_lang_Object + with java_io_Serializable { + @override + final String tag__ = 'platform'; +} + +mixin java_io_Serializable on java_lang_Object { + static java_io_Serializable subInstance() { + return _java_io_Serializable_SUB(); + } + + @override + final String tag__ = 'platform'; +} diff --git a/lib/src/type/platform/android_type/java/lang/object.dart b/lib/src/type/platform/android_type/java/lang/object.dart new file mode 100644 index 0000000..e2719db --- /dev/null +++ b/lib/src/type/platform/android_type/java/lang/object.dart @@ -0,0 +1,7 @@ +import 'package:foundation_fluttify/src/type/core/ref.dart'; + +// ignore_for_file: non_constant_identifier_names, camel_case_types, missing_return, unused_import +class java_lang_Object extends Ref { + @override + final String tag__ = 'platform'; +} diff --git a/lib/src/type/platform/android_type/java/lang/throwable.dart b/lib/src/type/platform/android_type/java/lang/throwable.dart new file mode 100644 index 0000000..e97e4de --- /dev/null +++ b/lib/src/type/platform/android_type/java/lang/throwable.dart @@ -0,0 +1,7 @@ +import 'package:foundation_fluttify/src/type/core/ref.dart'; + +// ignore_for_file: non_constant_identifier_names, camel_case_types, missing_return, unused_import +class java_lang_Throwable extends Ref { + @override + final String tag__ = 'platform'; +} diff --git a/lib/src/type/platform/android_type/org/json/json_object.dart b/lib/src/type/platform/android_type/org/json/json_object.dart new file mode 100644 index 0000000..628f20a --- /dev/null +++ b/lib/src/type/platform/android_type/org/json/json_object.dart @@ -0,0 +1,7 @@ +import 'package:foundation_fluttify/src/type/platform/android_type/java/lang/object.dart'; + +// ignore_for_file: non_constant_identifier_names, camel_case_types, missing_return, unused_import +class org_json_JSONObject extends java_lang_Object { + @override + final String tag__ = 'platform'; +} diff --git a/lib/src/type/platform/ios_type/av_audio_session_category_options.dart b/lib/src/type/platform/ios_type/av_audio_session_category_options.dart new file mode 100644 index 0000000..640ea41 --- /dev/null +++ b/lib/src/type/platform/ios_type/av_audio_session_category_options.dart @@ -0,0 +1,26 @@ +//typedef NS_OPTIONS(NSUInteger, AVAudioSessionCategoryOptions) +//{ +// /* MixWithOthers is only valid with AVAudioSessionCategoryPlayAndRecord, AVAudioSessionCategoryPlayback, and AVAudioSessionCategoryMultiRoute */ +// AVAudioSessionCategoryOptionMixWithOthers = 0x1, +// /* DuckOthers is only valid with AVAudioSessionCategoryAmbient, AVAudioSessionCategoryPlayAndRecord, AVAudioSessionCategoryPlayback, and AVAudioSessionCategoryMultiRoute */ +// AVAudioSessionCategoryOptionDuckOthers = 0x2, +// /* AllowBluetooth is only valid with AVAudioSessionCategoryRecord and AVAudioSessionCategoryPlayAndRecord */ +// AVAudioSessionCategoryOptionAllowBluetooth API_UNAVAILABLE(tvos, watchos, macos) = 0x4, +// /* DefaultToSpeaker is only valid with AVAudioSessionCategoryPlayAndRecord */ +// AVAudioSessionCategoryOptionDefaultToSpeaker API_UNAVAILABLE(tvos, watchos, macos) = 0x8, +// /* InterruptSpokenAudioAndMixWithOthers is only valid with AVAudioSessionCategoryPlayAndRecord, AVAudioSessionCategoryPlayback, and AVAudioSessionCategoryMultiRoute */ +// AVAudioSessionCategoryOptionInterruptSpokenAudioAndMixWithOthers API_AVAILABLE(ios(9.0), watchos(2.0), tvos(9.0)) API_UNAVAILABLE(macos) = 0x11, +// /* AllowBluetoothA2DP is only valid with AVAudioSessionCategoryPlayAndRecord */ +// AVAudioSessionCategoryOptionAllowBluetoothA2DP API_AVAILABLE(ios(10.0), watchos(3.0), tvos(10.0)) API_UNAVAILABLE(macos) = 0x20, +// /* AllowAirPlay is only valid with AVAudioSessionCategoryPlayAndRecord */ +// AVAudioSessionCategoryOptionAllowAirPlay API_AVAILABLE(ios(10.0), tvos(10.0)) API_UNAVAILABLE(watchos, macos) = 0x40, +//}; +enum AVAudioSessionCategoryOptions { + AVAudioSessionCategoryOptionMixWithOthers, + AVAudioSessionCategoryOptionDuckOthers, + AVAudioSessionCategoryOptionAllowBluetooth, + AVAudioSessionCategoryOptionDefaultToSpeaker, + AVAudioSessionCategoryOptionInterruptSpokenAudioAndMixWithOthers, + AVAudioSessionCategoryOptionAllowBluetoothA2DP, + AVAudioSessionCategoryOptionAllowAirPlay +} diff --git a/lib/src/type/platform/ios_type/ca_action.dart b/lib/src/type/platform/ios_type/ca_action.dart new file mode 100644 index 0000000..dd96f3a --- /dev/null +++ b/lib/src/type/platform/ios_type/ca_action.dart @@ -0,0 +1,7 @@ +// ignore_for_file: non_constant_identifier_names +import 'package:foundation_fluttify/foundation_fluttify.dart'; + +mixin CAAction on NSObject { + @override + final String tag__ = 'platform'; +} diff --git a/lib/src/type/platform/ios_type/ca_animation.dart b/lib/src/type/platform/ios_type/ca_animation.dart new file mode 100644 index 0000000..ef93f89 --- /dev/null +++ b/lib/src/type/platform/ios_type/ca_animation.dart @@ -0,0 +1,9 @@ +// ignore_for_file: non_constant_identifier_names +import 'package:foundation_fluttify/foundation_fluttify.dart'; + +import 'ca_media_timing.dart'; + +class CAAnimation extends NSObject with NSCopying, CAMediaTiming { + @override + final String tag__ = 'platform'; +} diff --git a/lib/src/type/platform/ios_type/ca_basic_animation.dart b/lib/src/type/platform/ios_type/ca_basic_animation.dart new file mode 100644 index 0000000..47d4ad9 --- /dev/null +++ b/lib/src/type/platform/ios_type/ca_basic_animation.dart @@ -0,0 +1,18 @@ +// ignore_for_file: non_constant_identifier_names +import 'ca_property_animation.dart'; + +class CABasicAnimation extends CAPropertyAnimation { + CABasicAnimation(this.fromValue, this.toValue, this.byValue); + + @override + final String tag__ = 'platform'; + + final dynamic fromValue; + final dynamic toValue; + final dynamic byValue; + + @override + String toString() { + return 'CABasicAnimation{fromValue: $fromValue, toValue: $toValue, byValue: $byValue}'; + } +} diff --git a/lib/src/type/platform/ios_type/ca_media_timing.dart b/lib/src/type/platform/ios_type/ca_media_timing.dart new file mode 100644 index 0000000..ba7f179 --- /dev/null +++ b/lib/src/type/platform/ios_type/ca_media_timing.dart @@ -0,0 +1,52 @@ +// ignore_for_file: non_constant_identifier_names + + + +import 'package:foundation_fluttify/foundation_fluttify.dart'; + +mixin CAMediaTiming on NSObject { + @override + final String tag__ = 'platform'; + + /// The begin time of the object, in relation to its parent object, if + /// applicable. Defaults to 0. + double? beginTime; + + /// The basic duration of the object. Defaults to 0. + double? duration; + + /// The rate of the layer. Used to scale parent time to local time, e.g. + /// if rate is 2, local time progresses twice as fast as parent time. + /// Defaults to 1. + double? speed; + + /// Additional offset in active local time. i.e. to convert from parent + /// time tp to active local time t: t = (tp - begin) * speed + offset. + /// One use of this is to "pause" a layer by setting `speed' to zero and + /// `offset' to a suitable value. Defaults to 0. */ + double? timeOffset; + + /// The repeat count of the object. May be fractional. Defaults to 0. + double? repeatCount; + + /// The repeat duration of the object. Defaults to 0. + double? repeatDuration; + + /// When true, the object plays backwards after playing forwards. Defaults + /// to NO. + bool? autoreverses; + + /// Defines how the timed object behaves outside its active duration. + /// Local time may be clamped to either end of the active duration, or + /// the element may be removed from the presentation. The legal values + /// are `backwards', `forwards', `both' and `removed'. Defaults to + /// `removed'. + bool? fillMode; +} + +enum CAMediaTimingFillMode { + backwards, + forwards, + both, + removed, +} diff --git a/lib/src/type/platform/ios_type/ca_property_animation.dart b/lib/src/type/platform/ios_type/ca_property_animation.dart new file mode 100644 index 0000000..58ace8e --- /dev/null +++ b/lib/src/type/platform/ios_type/ca_property_animation.dart @@ -0,0 +1,7 @@ +// ignore_for_file: non_constant_identifier_names +import 'ca_animation.dart'; + +class CAPropertyAnimation extends CAAnimation { + @override + final String tag__ = 'platform'; +} diff --git a/lib/src/type/platform/ios_type/cg_point.dart b/lib/src/type/platform/ios_type/cg_point.dart new file mode 100644 index 0000000..e550060 --- /dev/null +++ b/lib/src/type/platform/ios_type/cg_point.dart @@ -0,0 +1,54 @@ +// ignore_for_file: non_constant_identifier_names + +import 'dart:math'; + +import 'package:foundation_fluttify/foundation_fluttify.dart'; +import 'package:foundation_fluttify/src/object/obejcts.dart'; + +class CGPoint extends Ref { + @override + final String tag__ = 'platform'; + + static Future create(double x, double y) async { + final result = await kMethodChannel + .invokeMethod('CGPoint::create', {'x': x, 'y': y}); + return CGPoint()..refId = result?.refId; + } + + static Future createWithPoint(Point point) async { + final result = await kMethodChannel + .invokeMethod('CGPoint::create', {'x': point.x, 'y': point.y}); + return CGPoint()..refId = result?.refId; + } + + static Future> create_batch( + List x, + List y, + ) async { + final resultBatch = await kMethodChannel + .invokeListMethod('CGPoint::create_batch', {'x': x, 'y': y}); + return [ + for (final item in resultBatch ?? []) CGPoint()..refId = item.refId + ]; + } + + Future get x { + return kMethodChannel.invokeMethod('CGPoint::getX', {'__this__': this}); + } + + Future get y { + return kMethodChannel.invokeMethod('CGPoint::getY', {'__this__': this}); + } +} + +extension CGPointListX on List { + Future?> get x_batch { + return kMethodChannel + .invokeMethod('CGPoint::getX_batch', {'__this__': this}); + } + + Future?> get y_batch { + return kMethodChannel + .invokeMethod('CGPoint::getY_batch', {'__this__': this}); + } +} diff --git a/lib/src/type/platform/ios_type/cg_rect.dart b/lib/src/type/platform/ios_type/cg_rect.dart new file mode 100644 index 0000000..4d81fd9 --- /dev/null +++ b/lib/src/type/platform/ios_type/cg_rect.dart @@ -0,0 +1,39 @@ +// ignore_for_file: non_constant_identifier_names + +import 'package:foundation_fluttify/foundation_fluttify.dart'; + +class CGRect extends Ref { + @override + final String tag__ = 'platform'; + + static Future create( + double x, + double y, + double width, + double height, + ) async { + final result = await kMethodChannel.invokeMethod('CGRect::create', { + 'x': x, + 'y': y, + 'width': width, + 'height': height, + }); + return CGRect()..refId = result?.refId; + } + + Future get x { + return kMethodChannel.invokeMethod('CGRect::getX', {'__this__': this}); + } + + Future get y { + return kMethodChannel.invokeMethod('CGRect::getY', {'__this__': this}); + } + + Future get width { + return kMethodChannel.invokeMethod('CGRect::getWidth', {'__this__': this}); + } + + Future get height { + return kMethodChannel.invokeMethod('CGRect::getHeight', {'__this__': this}); + } +} diff --git a/lib/src/type/platform/ios_type/cg_size.dart b/lib/src/type/platform/ios_type/cg_size.dart new file mode 100644 index 0000000..3936e12 --- /dev/null +++ b/lib/src/type/platform/ios_type/cg_size.dart @@ -0,0 +1,27 @@ +// ignore_for_file: non_constant_identifier_names + +import 'package:foundation_fluttify/foundation_fluttify.dart'; + +class CGSize extends Ref { + @override + final String tag__ = 'platform'; + + static Future create( + double width, + double height, + ) async { + final result = await kMethodChannel.invokeMethod('CGSize::create', { + 'width': width, + 'height': height, + }); + return CGSize()..refId = result?.refId; + } + + Future get width { + return kMethodChannel.invokeMethod('CGSize::getWidth', {'__this__': this}); + } + + Future get height { + return kMethodChannel.invokeMethod('CGSize::getHeight', {'__this__': this}); + } +} diff --git a/lib/src/type/platform/ios_type/ns_coding.dart b/lib/src/type/platform/ios_type/ns_coding.dart new file mode 100644 index 0000000..5428673 --- /dev/null +++ b/lib/src/type/platform/ios_type/ns_coding.dart @@ -0,0 +1,12 @@ +// ignore_for_file: non_constant_identifier_names +import 'ns_object.dart'; + +// ignore: camel_case_types +class _NSCoding_SUB extends NSObject with NSCoding {} + +mixin NSCoding on NSObject { + @override + final String tag__ = 'platform'; + + static NSCoding subInstance() => _NSCoding_SUB(); +} diff --git a/lib/src/type/platform/ios_type/ns_copying.dart b/lib/src/type/platform/ios_type/ns_copying.dart new file mode 100644 index 0000000..3dae51c --- /dev/null +++ b/lib/src/type/platform/ios_type/ns_copying.dart @@ -0,0 +1,12 @@ +// ignore_for_file: non_constant_identifier_names +import 'ns_object.dart'; + +// ignore: camel_case_types +class _NSCopying_SUB extends NSObject with NSCopying {} + +mixin NSCopying on NSObject { + @override + final String tag__ = 'platform'; + + static NSCopying subInstance() => _NSCopying_SUB(); +} diff --git a/lib/src/type/platform/ios_type/ns_data.dart b/lib/src/type/platform/ios_type/ns_data.dart new file mode 100644 index 0000000..2ec7b22 --- /dev/null +++ b/lib/src/type/platform/ios_type/ns_data.dart @@ -0,0 +1,24 @@ +// ignore_for_file: non_constant_identifier_names + +import 'dart:typed_data'; + +import 'package:foundation_fluttify/foundation_fluttify.dart'; +import 'package:foundation_fluttify/src/object/obejcts.dart'; + +class NSData extends NSObject { + @override + final String tag__ = 'platform'; + + static Future createWithUint8List(Uint8List data) async { + final result = await kMethodChannel + .invokeMethod('NSData::createWithUint8List', {'data': data}); + return NSData()..refId = result?.refId; + } + + Future getData() { + return kMethodChannel.invokeMethod( + 'NSData::getData', + {'__this__': this}, + ); + } +} diff --git a/lib/src/type/platform/ios_type/ns_date.dart b/lib/src/type/platform/ios_type/ns_date.dart new file mode 100644 index 0000000..99a7091 --- /dev/null +++ b/lib/src/type/platform/ios_type/ns_date.dart @@ -0,0 +1,19 @@ +// ignore_for_file: non_constant_identifier_names + + + +import 'package:foundation_fluttify/foundation_fluttify.dart'; +import 'package:foundation_fluttify/src/object/obejcts.dart'; + +class NSDate extends NSObject { + @override + final String tag__ = 'platform'; + + /// 时间戳 单位秒 + Future get timeIntervalSince1970 { + return kMethodChannel.invokeMethod( + 'NSDate::get_timeIntervalSince1970', + {'__this__': this}, + ); + } +} diff --git a/lib/src/type/platform/ios_type/ns_error.dart b/lib/src/type/platform/ios_type/ns_error.dart new file mode 100644 index 0000000..6d3848a --- /dev/null +++ b/lib/src/type/platform/ios_type/ns_error.dart @@ -0,0 +1,24 @@ +// ignore_for_file: non_constant_identifier_names + + + +import 'package:foundation_fluttify/foundation_fluttify.dart'; + +import 'ns_object.dart'; + +class NSError extends NSObject { + @override + final String tag__ = 'platform'; + + Future get code async { + final int? errorCode = await kMethodChannel + .invokeMethod('NSError::getCode', {'__this__': this}); + return errorCode; + } + + Future get description async { + final String? description = await kMethodChannel + .invokeMethod('NSError::getDescription', {'__this__': this}); + return description; + } +} diff --git a/lib/src/type/platform/ios_type/ns_mutable_copying.dart b/lib/src/type/platform/ios_type/ns_mutable_copying.dart new file mode 100644 index 0000000..274ac16 --- /dev/null +++ b/lib/src/type/platform/ios_type/ns_mutable_copying.dart @@ -0,0 +1,11 @@ +// ignore_for_file: non_constant_identifier_names +import 'ns_object.dart'; + +class _NSMutableCopying_SUB extends NSObject with NSMutableCopying {} + +mixin NSMutableCopying on NSObject { + static NSMutableCopying subInstance() => _NSMutableCopying_SUB(); + + @override + final String tag__ = 'platform'; +} diff --git a/lib/src/type/platform/ios_type/ns_object.dart b/lib/src/type/platform/ios_type/ns_object.dart new file mode 100644 index 0000000..17088ff --- /dev/null +++ b/lib/src/type/platform/ios_type/ns_object.dart @@ -0,0 +1,10 @@ +// ignore_for_file: non_constant_identifier_names + +import 'package:foundation_fluttify/foundation_fluttify.dart'; + +class NSObject extends Ref { + @override + final String tag__ = 'platform'; +} + +extension NSObjectListX on List {} diff --git a/lib/src/type/platform/ios_type/ns_operation.dart b/lib/src/type/platform/ios_type/ns_operation.dart new file mode 100644 index 0000000..1ca517f --- /dev/null +++ b/lib/src/type/platform/ios_type/ns_operation.dart @@ -0,0 +1,7 @@ +// ignore_for_file: non_constant_identifier_names +import 'ns_object.dart'; + +class NSOperation extends NSObject { + @override + final String tag__ = 'platform'; +} diff --git a/lib/src/type/platform/ios_type/ns_url.dart b/lib/src/type/platform/ios_type/ns_url.dart new file mode 100644 index 0000000..2dd9150 --- /dev/null +++ b/lib/src/type/platform/ios_type/ns_url.dart @@ -0,0 +1,7 @@ +// ignore_for_file: non_constant_identifier_names +import 'package:foundation_fluttify/foundation_fluttify.dart'; + +class NSURL extends NSObject { + @override + final String tag__ = 'platform'; +} diff --git a/lib/src/type/platform/ios_type/ns_user_activity.dart b/lib/src/type/platform/ios_type/ns_user_activity.dart new file mode 100644 index 0000000..c3e8419 --- /dev/null +++ b/lib/src/type/platform/ios_type/ns_user_activity.dart @@ -0,0 +1,7 @@ +// ignore_for_file: non_constant_identifier_names +import 'package:foundation_fluttify/foundation_fluttify.dart'; + +class NSUserActivity extends NSObject { + @override + final String tag__ = 'platform'; +} diff --git a/lib/src/type/platform/ios_type/ns_value.dart b/lib/src/type/platform/ios_type/ns_value.dart new file mode 100644 index 0000000..030b7b2 --- /dev/null +++ b/lib/src/type/platform/ios_type/ns_value.dart @@ -0,0 +1,7 @@ +// ignore_for_file: non_constant_identifier_names +import 'package:foundation_fluttify/foundation_fluttify.dart'; + +class NSValue extends NSObject with NSCopying { + @override + final String tag__ = 'platform'; +} diff --git a/lib/src/type/platform/ios_type/ui_application.dart b/lib/src/type/platform/ios_type/ui_application.dart new file mode 100644 index 0000000..5dd4780 --- /dev/null +++ b/lib/src/type/platform/ios_type/ui_application.dart @@ -0,0 +1,7 @@ +// ignore_for_file: non_constant_identifier_names +import 'package:foundation_fluttify/foundation_fluttify.dart'; + +class UIApplication extends NSObject { + @override + final String tag__ = 'platform'; +} diff --git a/lib/src/type/platform/ios_type/ui_application_shortcut_item.dart b/lib/src/type/platform/ios_type/ui_application_shortcut_item.dart new file mode 100644 index 0000000..5452a45 --- /dev/null +++ b/lib/src/type/platform/ios_type/ui_application_shortcut_item.dart @@ -0,0 +1,7 @@ +// ignore_for_file: non_constant_identifier_names +import 'package:foundation_fluttify/foundation_fluttify.dart'; + +class UIApplicationShortcutItem extends NSObject { + @override + final String tag__ = 'platform'; +} diff --git a/lib/src/type/platform/ios_type/ui_bar_style.dart b/lib/src/type/platform/ios_type/ui_bar_style.dart new file mode 100644 index 0000000..5c898fa --- /dev/null +++ b/lib/src/type/platform/ios_type/ui_bar_style.dart @@ -0,0 +1,4 @@ +enum UIBarStyle { + UIBarStyleDefault, + UIBarStyleBlack, +} diff --git a/lib/src/type/platform/ios_type/ui_color.dart b/lib/src/type/platform/ios_type/ui_color.dart new file mode 100644 index 0000000..4997a21 --- /dev/null +++ b/lib/src/type/platform/ios_type/ui_color.dart @@ -0,0 +1,19 @@ +// ignore_for_file: non_constant_identifier_names + +import 'dart:ui'; + +import 'package:foundation_fluttify/foundation_fluttify.dart'; +import 'package:foundation_fluttify/src/object/obejcts.dart'; + +import 'ns_object.dart'; + +class UIColor extends NSObject { + @override + final String tag__ = 'platform'; + + static Future create(Color color) async { + final result = await kMethodChannel + .invokeMethod('UIColor::create', {'colorValue': color.value}); + return UIColor()..refId = result?.refId; + } +} diff --git a/lib/src/type/platform/ios_type/ui_control.dart b/lib/src/type/platform/ios_type/ui_control.dart new file mode 100644 index 0000000..d3f6de1 --- /dev/null +++ b/lib/src/type/platform/ios_type/ui_control.dart @@ -0,0 +1,7 @@ +// ignore_for_file: non_constant_identifier_names +import 'ns_object.dart'; + +class UIControl extends NSObject { + @override + final String tag__ = 'platform'; +} diff --git a/lib/src/type/platform/ios_type/ui_edge_insets.dart b/lib/src/type/platform/ios_type/ui_edge_insets.dart new file mode 100644 index 0000000..70af4cd --- /dev/null +++ b/lib/src/type/platform/ios_type/ui_edge_insets.dart @@ -0,0 +1,45 @@ +// ignore_for_file: non_constant_identifier_names + +import 'package:foundation_fluttify/foundation_fluttify.dart'; +import 'package:foundation_fluttify/src/object/obejcts.dart'; + +class UIEdgeInsets extends Ref { + @override + final String tag__ = 'platform'; + + static Future create( + double top, + double left, + double bottom, + double right, + ) async { + final result = + await kMethodChannel.invokeMethod('UIEdgeInsets::create', { + 'top': top, + 'left': left, + 'bottom': bottom, + 'right': right, + }); + return UIEdgeInsets()..refId = result?.refId; + } + + Future get top { + return kMethodChannel + .invokeMethod('UIEdgeInsets::getTop', {'__this__': this}); + } + + Future get left { + return kMethodChannel + .invokeMethod('UIEdgeInsets::getLeft', {'__this__': this}); + } + + Future get bottom { + return kMethodChannel + .invokeMethod('UIEdgeInsets::getBottom', {'__this__': this}); + } + + Future get right { + return kMethodChannel + .invokeMethod('UIEdgeInsets::getRight', {'__this__': this}); + } +} diff --git a/lib/src/type/platform/ios_type/ui_image.dart b/lib/src/type/platform/ios_type/ui_image.dart new file mode 100644 index 0000000..cca0a80 --- /dev/null +++ b/lib/src/type/platform/ios_type/ui_image.dart @@ -0,0 +1,53 @@ +// ignore_for_file: non_constant_identifier_names, camel_case_types, missing_return, unused_import + +import 'dart:typed_data'; + +import 'package:foundation_fluttify/foundation_fluttify.dart'; +import 'package:foundation_fluttify/src/object/obejcts.dart'; + +import 'ns_object.dart'; + +class UIImage extends NSObject { + @override + final String tag__ = 'platform'; + + static Future create(Uint8List bitmapBytes) async { + final result = await kMethodChannel.invokeMethod( + 'UIImage::createUIImage', + {'bitmapBytes': bitmapBytes}, + ); + return UIImage()..refId = result?.refId; + } + + static Future createWithPath( + String resource, + String type, + String fileName, + ) async { + final result = await kMethodChannel.invokeMethod( + 'UIImage::createWithPath', + { + 'resource': resource, + 'type': type, + 'fileName': fileName, + }, + ); + return UIImage()..refId = result?.refId; + } + + static Future> create_batch( + List bitmapBytesBatch, + ) async { + final resultBatch = await kMethodChannel.invokeListMethod( + 'UIImage::createUIImage_batch', + [ + for (final bitmapBytes in bitmapBytesBatch) {'bitmapBytes': bitmapBytes} + ], + ); + return resultBatch?.map((it) => UIImage()..refId = it.refId).toList() ?? []; + } + + Future get data { + return kMethodChannel.invokeMethod('UIImage::getData', {'__this__': this}); + } +} diff --git a/lib/src/type/platform/ios_type/ui_image_view.dart b/lib/src/type/platform/ios_type/ui_image_view.dart new file mode 100644 index 0000000..611cd58 --- /dev/null +++ b/lib/src/type/platform/ios_type/ui_image_view.dart @@ -0,0 +1,19 @@ +// ignore_for_file: non_constant_identifier_names + +import 'package:foundation_fluttify/foundation_fluttify.dart'; +import 'package:foundation_fluttify/src/object/obejcts.dart'; + +import 'ui_view.dart'; + +class UIImageView extends UIView { + @override + final String tag__ = 'platform'; + + static Future create(UIImage image) async { + final result = await kMethodChannel.invokeMethod( + 'UIImageView::create', + {'image': image}, + ); + return UIImageView()..refId = result?.refId; + } +} diff --git a/lib/src/type/platform/ios_type/ui_status_bar_style.dart b/lib/src/type/platform/ios_type/ui_status_bar_style.dart new file mode 100644 index 0000000..a5bf4c8 --- /dev/null +++ b/lib/src/type/platform/ios_type/ui_status_bar_style.dart @@ -0,0 +1,5 @@ +enum UIStatusBarStyle { + UIStatusBarStyleDefault, + UIStatusBarStyleLightContent, + UIStatusBarStyleDarkContent, +} diff --git a/lib/src/type/platform/ios_type/ui_user_notification_settings.dart b/lib/src/type/platform/ios_type/ui_user_notification_settings.dart new file mode 100644 index 0000000..6d4c369 --- /dev/null +++ b/lib/src/type/platform/ios_type/ui_user_notification_settings.dart @@ -0,0 +1,7 @@ +// ignore_for_file: non_constant_identifier_names +import 'package:foundation_fluttify/foundation_fluttify.dart'; + +class UIUserNotificationSettings extends NSObject { + @override + final String tag__ = 'platform'; +} diff --git a/lib/src/type/platform/ios_type/ui_view.dart b/lib/src/type/platform/ios_type/ui_view.dart new file mode 100644 index 0000000..df964e9 --- /dev/null +++ b/lib/src/type/platform/ios_type/ui_view.dart @@ -0,0 +1,163 @@ +// ignore_for_file: non_constant_identifier_names + +import 'dart:math'; + +import 'package:foundation_fluttify/foundation_fluttify.dart'; +import 'package:foundation_fluttify/src/object/obejcts.dart'; +import 'package:foundation_fluttify/src/type/platform/ios_type/cg_point.dart'; + +import 'cg_rect.dart'; +import 'ns_object.dart'; + +class UIView extends NSObject { + @override + final String tag__ = 'platform'; + + static Future create() async { + final result = await kMethodChannel.invokeMethod('UIView::create'); + return UIView()..refId = result?.refId; + } + + /// 旋转 + /// + /// 单位为度 + Future rotate(double angle) async { + await kMethodChannel.invokeMethod('UIView::rotate', { + '__this__': this, + 'angle': angle, + }); + } + + /// 执行缩放动画 + Future scaleWithDuration({ + Duration duration = const Duration(seconds: 1), + double fromValue = 0, + required double toValue, + int repeatCount = 0, + int repeatMode = 1, + }) async { + assert(fromValue >= 0); + assert(toValue >= 0); + await kMethodChannel.invokeMethod('UIView::scaleWithDuration', { + '__this__': this, + 'duration': duration.inMilliseconds / 1000, + 'fromValue': fromValue, + 'toValue': toValue, + 'repeatCount': repeatCount, + 'repeatMode': repeatMode, + }); + } + + /// 执行移动动画 + Future translateWithDuration({ + Duration duration = const Duration(seconds: 1), + required CGPoint toValue, + int repeatCount = 0, + int repeatMode = 1, + }) async { + await kMethodChannel.invokeMethod('UIView::translateWithDuration', { + '__this__': this, + 'duration': duration.inMilliseconds / 1000, + 'toX': await toValue.x, + 'toY': await toValue.y, + 'repeatCount': repeatCount, + 'repeatMode': repeatMode, + }); + } + + /// 执行透明度动画 + /// + /// 范围为0-1 + Future alphaWithDuration({ + Duration duration = const Duration(seconds: 1), + double fromValue = 0, + required double toValue, + int repeatCount = 0, + int repeatMode = 0, + }) async { + assert(fromValue >= 0 && fromValue <= 1); + assert(toValue >= 0 && toValue <= 1); + await kMethodChannel.invokeMethod('UIView::alphaWithDuration', { + '__this__': this, + 'duration': duration.inMilliseconds / 1000, + 'fromValue': fromValue, + 'toValue': toValue, + 'repeatCount': repeatCount, + 'repeatMode': repeatMode, + }); + } + + /// 执行旋转动画 + /// + /// 单位为度, 逆时针旋转 + Future rotateWithDuration({ + Duration duration = const Duration(seconds: 1), + double fromValue = 0, + required double toValue, + int repeatCount = 0, + int repeatMode = 0, + }) async { + await kMethodChannel.invokeMethod('UIView::rotateWithDuration', { + '__this__': this, + 'duration': duration.inMilliseconds / 1000, + 'fromValue': fromValue / 180 * pi, + 'toValue': -toValue / 180 * pi, + 'repeatCount': repeatCount, + 'repeatMode': repeatMode, + }); + } + + /// 执行组合动画 + /// + /// [keyPath]为构造CABasicAnimation时的[CABasicAnimation animationWithKeyPath:keyPath]; + /// 缩放为`transform.scale`, 透明度为`opacity`, 旋转为`transform.rotation` + /// + /// [fromValue], [toValue]和[keyPath]的长度必须相等 + Future groupWithDuration({ + Duration duration = const Duration(seconds: 1), + required List fromValue, + required List toValue, + required List keyPath, + int repeatCount = 0, + int repeatMode = 0, + }) async { + assert(fromValue.length == toValue.length); + assert(toValue.length == keyPath.length); + await kMethodChannel.invokeMethod('UIView::groupWithDuration', { + '__this__': this, + 'duration': duration.inMilliseconds / 1000, + 'fromValue': [for (final item in fromValue) item / 180 * pi], + 'toValue': [for (final item in fromValue) -item / 180 * pi], + 'keyPath': keyPath, + 'repeatCount': repeatCount, + 'repeatMode': repeatMode, + }); + } + + Future get frame async { + final result = await kMethodChannel + .invokeMethod('UIView::getFrame', {'__this__': this}); + return CGRect()..refId = result?.refId; + } + + Future get hidden async { + final result = await kMethodChannel + .invokeMethod('UIView::getHidden', {'__this__': this}); + return result; + } + + Future setHidden(bool hidden) async { + await kMethodChannel.invokeMethod('UIView::setHidden', { + '__this__': this, + 'hidden': hidden, + }); + } + + Future setAnchorPoint(double anchorU, double anchorV) async { + await kMethodChannel.invokeMethod('UIView::setAnchorPoint', { + '__this__': this, + 'anchorU': anchorU, + 'anchorV': anchorV, + }); + } +} diff --git a/lib/src/type/platform/ios_type/ui_view_controller.dart b/lib/src/type/platform/ios_type/ui_view_controller.dart new file mode 100644 index 0000000..f73e9bb --- /dev/null +++ b/lib/src/type/platform/ios_type/ui_view_controller.dart @@ -0,0 +1,16 @@ +// ignore_for_file: non_constant_identifier_names + +import 'package:foundation_fluttify/foundation_fluttify.dart'; + +import 'ns_object.dart'; + +class UIViewController extends NSObject { + @override + final String tag__ = 'platform'; + + static Future get() async { + final result = + await kMethodChannel.invokeMethod('UIViewController::get'); + return UIViewController()..refId = result?.refId; + } +} diff --git a/lib/src/type/widget/android_opengl_GLSurfaceView.widget.dart b/lib/src/type/widget/android_opengl_GLSurfaceView.widget.dart new file mode 100644 index 0000000..eefbbfd --- /dev/null +++ b/lib/src/type/widget/android_opengl_GLSurfaceView.widget.dart @@ -0,0 +1,75 @@ +// ignore_for_file: non_constant_identifier_names, camel_case_types, missing_return, unused_import + + + +import 'dart:io'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:foundation_fluttify/foundation_fluttify.dart'; +import 'package:foundation_fluttify/src/type/platform/ios_type/ui_view.dart'; + +typedef _OnViewCreated = Future Function( + android_opengl_GLSurfaceView? controller, +); +typedef _OnViewDispose = Future Function(); + +class android_opengl_GLSurfaceViewWidget extends StatefulWidget { + const android_opengl_GLSurfaceViewWidget({ + Key? key, + this.onGLSurfaceViewCreated, + this.onDispose, + this.gestureRecognizers, + }) : super(key: key); + + final _OnViewCreated? onGLSurfaceViewCreated; + final _OnViewDispose? onDispose; + final Set>? gestureRecognizers; + + @override + _android_opengl_GLSurfaceViewWidgetState createState() => + _android_opengl_GLSurfaceViewWidgetState(); +} + +class _android_opengl_GLSurfaceViewWidgetState + extends State { + android_opengl_GLSurfaceView? _view; + + @override + Widget build(BuildContext context) { + if (Platform.isAndroid) { + final gestureRecognizers = widget.gestureRecognizers ?? + >{ + Factory( + () => EagerGestureRecognizer()), + }; + final messageCodec = FluttifyMessageCodec(tag: 'platform'); + return AndroidView( + viewType: 'me.yohom/foundation_fluttify/android.opengl.GLSurfaceView', + creationParamsCodec: messageCodec, + gestureRecognizers: gestureRecognizers, + onPlatformViewCreated: (viewId) async { + final refId = await viewId2RefId((2147483647 - viewId).toString()); + _view = android_opengl_GLSurfaceView() + ..refId = 'android.opengl.GLSurfaceView:$refId'; + if (widget.onGLSurfaceViewCreated != null) { + await widget.onGLSurfaceViewCreated!(_view); + } + }, + ); + } else { + return Center(child: Text('不支持的平台')); + } + } + + @override + void dispose() { + if (widget.onDispose != null) { + widget.onDispose!().then((_) => _view!.release__()); + } else { + _view!.release__(); + } + super.dispose(); + } +} diff --git a/lib/src/type/widget/android_view_SurfaceView.widget.dart b/lib/src/type/widget/android_view_SurfaceView.widget.dart new file mode 100644 index 0000000..ce26a6d --- /dev/null +++ b/lib/src/type/widget/android_view_SurfaceView.widget.dart @@ -0,0 +1,128 @@ +// ignore_for_file: non_constant_identifier_names, camel_case_types, missing_return, unused_import + +import 'dart:io'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:foundation_fluttify/foundation_fluttify.dart'; +import 'package:foundation_fluttify/src/type/platform/ios_type/ui_view.dart'; + +typedef _OnViewCreated = Future Function( + android_view_SurfaceView? controller, +); +typedef _OnViewDispose = Future Function(); + +class android_view_SurfaceViewWidget extends StatefulWidget { + const android_view_SurfaceViewWidget({ + Key? key, + this.onSurfaceViewCreated, + this.surfaceCreated, + this.surfaceChanged, + this.surfaceDestroyed, + this.onDispose, + this.gestureRecognizers, + }) : super(key: key); + + final _OnViewCreated? onSurfaceViewCreated; + final ValueChanged? surfaceCreated; + final void Function(android_view_SurfaceHolder, int?, int?, int?)? + surfaceChanged; + final ValueChanged? surfaceDestroyed; + final _OnViewDispose? onDispose; + final Set>? gestureRecognizers; + + @override + _android_view_SurfaceViewWidgetState createState() => + _android_view_SurfaceViewWidgetState(); +} + +class _android_view_SurfaceViewWidgetState + extends State { + android_view_SurfaceView? _view; + + @override + void initState() { + super.initState(); + MethodChannel( + 'android.view.SurfaceHolder::addCallback::Callback', + kMethodCodec, + ).setMethodCallHandler((methodCall) async { + try { + final args = methodCall.arguments as Map?; + switch (methodCall.method) { + case 'Callback::android.view.SurfaceHolder.Callback::surfaceCreated': + if (widget.surfaceCreated != null) { + final ref = args!['holder'] as Ref; + widget.surfaceCreated!( + android_view_SurfaceHolder.subInstance()..refId = ref.refId, + ); + } + break; + case 'Callback::android.view.SurfaceHolder.Callback::surfaceChanged': + if (widget.surfaceChanged != null) { + final ref = args!['holder'] as Ref; + widget.surfaceChanged!( + android_view_SurfaceHolder.subInstance()..refId = ref.refId, + args['format'], + args['width'], + args['height'], + ); + } + break; + case 'Callback::android.view.SurfaceHolder.Callback::surfaceDestroyed': + if (widget.surfaceDestroyed != null) { + final ref = args!['holder'] as Ref; + widget.surfaceDestroyed!( + android_view_SurfaceHolder.subInstance()..refId = ref.refId, + ); + } + break; + default: + throw MissingPluginException('方法${methodCall.method}未实现'); + } + } catch (e) { + debugPrint(e.toString()); + rethrow; + } + }); + } + + @override + Widget build(BuildContext context) { + if (Platform.isAndroid) { + final gestureRecognizers = widget.gestureRecognizers ?? + >{ + Factory( + () => EagerGestureRecognizer()), + }; + final messageCodec = FluttifyMessageCodec(); + return AndroidView( + viewType: 'me.yohom/foundation_fluttify/android.view.SurfaceView', + creationParamsCodec: messageCodec, + gestureRecognizers: gestureRecognizers, + onPlatformViewCreated: (viewId) async { + final refId = await viewId2RefId((2147483647 - viewId).toString()); + _view = android_view_SurfaceView() + ..refId = 'android.view.SurfaceView:$refId'; + if (widget.onSurfaceViewCreated != null) { + await widget.onSurfaceViewCreated!(_view); + } + }, + ); + } else { + return Center(child: Text('不支持的平台')); + } + } + + @override + void dispose() { + if (widget.onDispose != null) { + widget.onDispose!().then((_) => _view!.release__()); + } else { + _view!.release__(); + } + super.dispose(); + } +} diff --git a/lib/src/type/widget/android_widget_FrameLayout.widget.dart b/lib/src/type/widget/android_widget_FrameLayout.widget.dart new file mode 100644 index 0000000..906890e --- /dev/null +++ b/lib/src/type/widget/android_widget_FrameLayout.widget.dart @@ -0,0 +1,74 @@ +// ignore_for_file: non_constant_identifier_names, camel_case_types, missing_return, unused_import + + + +import 'dart:io'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:foundation_fluttify/foundation_fluttify.dart'; +import 'package:foundation_fluttify/src/type/platform/ios_type/ui_view.dart'; + +typedef _OnViewCreated = Future Function( + android_widget_FrameLayout? controller); +typedef _OnViewDispose = Future Function(); + +class android_view_FrameLayoutWidget extends StatefulWidget { + const android_view_FrameLayoutWidget({ + Key? key, + this.onFrameLayoutCreated, + this.onDispose, + this.gestureRecognizers, + }) : super(key: key); + + final _OnViewCreated? onFrameLayoutCreated; + final _OnViewDispose? onDispose; + final Set>? gestureRecognizers; + + @override + _android_view_FrameLayoutWidgetState createState() => + _android_view_FrameLayoutWidgetState(); +} + +class _android_view_FrameLayoutWidgetState + extends State { + android_widget_FrameLayout? _view; + + @override + Widget build(BuildContext context) { + if (Platform.isAndroid) { + final gestureRecognizers = widget.gestureRecognizers ?? + >{ + Factory( + () => EagerGestureRecognizer()), + }; + final messageCodec = FluttifyMessageCodec(); + return AndroidView( + viewType: 'me.yohom/foundation_fluttify/android.widget.FrameLayout', + creationParamsCodec: messageCodec, + gestureRecognizers: gestureRecognizers, + onPlatformViewCreated: (viewId) async { + final refId = await viewId2RefId((2147483647 - viewId).toString()); + _view = android_widget_FrameLayout() + ..refId = 'android.widget.FrameLayout:$refId'; + if (widget.onFrameLayoutCreated != null) { + await widget.onFrameLayoutCreated!(_view); + } + }, + ); + } else { + return Center(child: Text('不支持的平台')); + } + } + + @override + void dispose() { + if (widget.onDispose != null) { + widget.onDispose!().then((_) => _view!.release__()); + } else { + _view!.release__(); + } + super.dispose(); + } +} diff --git a/lib/src/type/widget/scoped_release_pool.widget.dart b/lib/src/type/widget/scoped_release_pool.widget.dart new file mode 100644 index 0000000..ee42330 --- /dev/null +++ b/lib/src/type/widget/scoped_release_pool.widget.dart @@ -0,0 +1,52 @@ +import 'package:flutter/material.dart'; +import 'package:foundation_fluttify/foundation_fluttify.dart'; +import 'package:foundation_fluttify/src/type/core/ref.dart'; + +class ScopedReleasePool extends StatefulWidget { + const ScopedReleasePool({ + Key? key, + required this.child, + required this.tag, + }) : super(key: key); + + final Widget child; + + /// 标记一类对象 + /// + /// 如果设置了, 则释放时根据这个tag进行释放, 防止误伤 + final String tag; + + @override + ScopedReleasePoolState createState() => ScopedReleasePoolState(); +} + +class ScopedReleasePoolState extends State { + final Set _releasePool = {}; + + @override + void initState() { + super.initState(); + gReleasePoolStack.push(this); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } + + @override + void dispose() { + log('ScopedReleasePool释放对象: $_releasePool'); + gReleasePoolStack.pop(); + _releasePool + // 过滤出tag为目标tag的对象进行释放 或 tag为null表示不过滤 + .where((e) => e.tag__ == widget.tag) + .release_batch() + .then((value) => _releasePool.clear()); + super.dispose(); + } + + void add(Ref ref) { + _releasePool.add(ref); + } +} diff --git a/lib/src/type/widget/ui_view.widget.dart b/lib/src/type/widget/ui_view.widget.dart new file mode 100644 index 0000000..537cddc --- /dev/null +++ b/lib/src/type/widget/ui_view.widget.dart @@ -0,0 +1,65 @@ +import 'dart:io'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:foundation_fluttify/foundation_fluttify.dart'; + +typedef OnUIViewCreated = Future Function(UIView? controller); +typedef _OnUiKitViewDispose = Future Function(); + +class UIViewWidget extends StatefulWidget { + const UIViewWidget({ + Key? key, + this.onUIViewCreated, + this.onDispose, + this.gestureRecognizers, + }) : super(key: key); + + final OnUIViewCreated? onUIViewCreated; + final _OnUiKitViewDispose? onDispose; + final Set>? gestureRecognizers; + + @override + _UIViewWidgetState createState() => _UIViewWidgetState(); +} + +class _UIViewWidgetState extends State { + UIView? _view; + + @override + Widget build(BuildContext context) { + if (Platform.isIOS) { + final gestureRecognizers = widget.gestureRecognizers ?? + >{ + Factory( + () => EagerGestureRecognizer()), + }; + final messageCodec = FluttifyMessageCodec(); + return UiKitView( + viewType: 'me.yohom/foundation_fluttify/UIView', + creationParamsCodec: messageCodec, + gestureRecognizers: gestureRecognizers, + onPlatformViewCreated: (viewId) async { + final refId = await viewId2RefId((2147483647 - viewId).toString()); + _view = UIView()..refId = 'UIView:$refId'; + if (widget.onUIViewCreated != null) { + await widget.onUIViewCreated!(_view); + } + }, + ); + } else { + return Center(child: Text('不支持的平台')); + } + } + + @override + void dispose() { + if (widget.onDispose != null) { + widget.onDispose!().then((_) => _view?.release__()); + } else { + _view?.release__(); + } + super.dispose(); + } +} diff --git a/pubspec.lock b/pubspec.lock new file mode 100644 index 0000000..4838d6b --- /dev/null +++ b/pubspec.lock @@ -0,0 +1,189 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + async: + dependency: transitive + description: + name: async + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" + source: hosted + version: "2.11.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + characters: + dependency: transitive + description: + name: characters + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + url: "https://pub.dev" + source: hosted + version: "1.3.0" + clock: + dependency: transitive + description: + name: clock + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" + source: hosted + version: "1.1.1" + collection: + dependency: transitive + description: + name: collection + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + url: "https://pub.dev" + source: hosted + version: "1.18.0" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" + source: hosted + version: "1.3.1" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" + url: "https://pub.dev" + source: hosted + version: "10.0.5" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" + url: "https://pub.dev" + source: hosted + version: "3.0.5" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + url: "https://pub.dev" + source: hosted + version: "3.0.1" + matcher: + dependency: transitive + description: + name: matcher + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + url: "https://pub.dev" + source: hosted + version: "0.12.16+1" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + url: "https://pub.dev" + source: hosted + version: "0.11.1" + meta: + dependency: transitive + description: + name: meta + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 + url: "https://pub.dev" + source: hosted + version: "1.15.0" + path: + dependency: transitive + description: + name: path + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + url: "https://pub.dev" + source: hosted + version: "1.9.0" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_span: + dependency: transitive + description: + name: source_span + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + url: "https://pub.dev" + source: hosted + version: "1.10.0" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + url: "https://pub.dev" + source: hosted + version: "1.11.1" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + url: "https://pub.dev" + source: hosted + version: "2.1.2" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + test_api: + dependency: transitive + description: + name: test_api + sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" + url: "https://pub.dev" + source: hosted + version: "0.7.2" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" + url: "https://pub.dev" + source: hosted + version: "14.2.5" +sdks: + dart: ">=3.5.3 <4.0.0" + flutter: ">=3.18.0-18.0.pre.54" diff --git a/pubspec.yaml b/pubspec.yaml new file mode 100644 index 0000000..e081ddd --- /dev/null +++ b/pubspec.yaml @@ -0,0 +1,25 @@ +name: foundation_fluttify +description: Foundation for `Fluttify`. +version: 0.13.0+1 +homepage: https://github.com/fluttify-project/foundation_fluttify + +environment: + sdk: ^3.5.3 + flutter: '>=3.3.0' + +dependencies: + flutter: + sdk: flutter + +dev_dependencies: + flutter_test: + sdk: flutter + +flutter: + plugin: + platforms: + android: + package: me.yohom.foundation_fluttify + pluginClass: FoundationFluttifyPlugin + ios: + pluginClass: FoundationFluttifyPlugin \ No newline at end of file diff --git a/test/foundation_fluttify_test.dart b/test/foundation_fluttify_test.dart new file mode 100644 index 0000000..ab73b3a --- /dev/null +++ b/test/foundation_fluttify_test.dart @@ -0,0 +1 @@ +void main() {}