From 56b07540f8d7158c3ace9c1e984ac887442e7d44 Mon Sep 17 00:00:00 2001 From: Jarvanmo Date: Thu, 21 May 2026 16:07:20 +0800 Subject: [PATCH 1/2] migrate to KGP --- android/.gitignore | 9 - .../plugins/GeneratedPluginRegistrant.java | 19 - android/build.gradle.copy | 161 -- android/build.gradle.kts | 164 -- android/build.gradle.kts.bak | 56 - android/consumer-proguard-rules.txt | 38 - android/gen.gradle.kts | 32 - android/settings.gradle | 1 - android/src/main/AndroidManifest.xml | 46 - .../com/jarvan/fluwx/FluwxFileProvider.kt | 10 - .../kotlin/com/jarvan/fluwx/FluwxPlugin.kt | 541 ------ .../jarvan/fluwx/handlers/FluwxAuthHandler.kt | 83 - .../fluwx/handlers/FluwxRequestHandler.kt | 25 - .../fluwx/handlers/FluwxShareHandler.kt | 400 ----- .../fluwx/handlers/PermissionHandler.kt | 39 - .../com/jarvan/fluwx/handlers/WXAPiHandler.kt | 117 -- .../com/jarvan/fluwx/io/ByteArrayToFile.kt | 83 - .../kotlin/com/jarvan/fluwx/io/ImagesIO.kt | 131 -- .../kotlin/com/jarvan/fluwx/io/WeChatFiles.kt | 141 -- .../com/jarvan/fluwx/utils/FluwxExtensions.kt | 54 - .../com/jarvan/fluwx/utils/WXApiUtils.java | 66 - .../fluwx/wxapi/FluwxWXEntryActivity.kt | 40 - android/src/main/res/values/styles.xml | 8 - .../res/xml/fluwx_file_provider_paths.xml | 5 - .../com/jarvan/fluwx/FluwxPluginTest.kt | 14 - ios/.gitignore | 38 - ios/Assets/.gitkeep | 0 ios/Classes/FluwxDelegate.m | 27 - ios/Classes/FluwxPlugin.m | 1596 ----------------- ios/Classes/FluwxStringUtil.h | 12 - ios/Classes/FluwxStringUtil.m | 24 - ios/Classes/NSStringWrapper.h | 64 - ios/Classes/NSStringWrapper.m | 153 -- ios/Classes/ThumbnailHelper.h | 17 - ios/Classes/ThumbnailHelper.m | 134 -- ios/Classes/public/FluwxDelegate.h | 19 - ios/Classes/public/FluwxPlugin.h | 4 - ios/Resources/PrivacyInfo.xcprivacy | 23 - ios/fluwx.podspec | 121 -- ios/wechat_setup.rb | 168 -- ohos/.gitignore | 10 - ohos/build-profile.json5 | 10 - ohos/hvigorfile.ts | 2 - ohos/index.ets | 17 - ohos/local.properties | 1 - ohos/oh-package.json5 | 12 - .../ets/components/plugin/FluwxPlugin.ets | 299 --- .../plugin/handlers/FluwxAuthHandler.ets | 88 - .../plugin/handlers/FluwxShareHandler.ets | 241 --- .../plugin/handlers/WXAPiHandler.ets | 65 - ohos/src/main/module.json5 | 10 - packages/_shared/android/build.gradle.kts | 27 +- .../gradle/wrapper/gradle-wrapper.properties | 2 +- .../fluwx/example/android/settings.gradle.kts | 4 +- .../example/android/app/build.gradle.kts | 11 +- .../gradle/wrapper/gradle-wrapper.properties | 2 +- .../example/android/settings.gradle.kts | 4 +- 57 files changed, 32 insertions(+), 5456 deletions(-) delete mode 100644 android/.gitignore delete mode 100644 android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java delete mode 100644 android/build.gradle.copy delete mode 100644 android/build.gradle.kts delete mode 100644 android/build.gradle.kts.bak delete mode 100644 android/consumer-proguard-rules.txt delete mode 100644 android/gen.gradle.kts delete mode 100644 android/settings.gradle delete mode 100644 android/src/main/AndroidManifest.xml delete mode 100644 android/src/main/kotlin/com/jarvan/fluwx/FluwxFileProvider.kt delete mode 100644 android/src/main/kotlin/com/jarvan/fluwx/FluwxPlugin.kt delete mode 100644 android/src/main/kotlin/com/jarvan/fluwx/handlers/FluwxAuthHandler.kt delete mode 100644 android/src/main/kotlin/com/jarvan/fluwx/handlers/FluwxRequestHandler.kt delete mode 100644 android/src/main/kotlin/com/jarvan/fluwx/handlers/FluwxShareHandler.kt delete mode 100644 android/src/main/kotlin/com/jarvan/fluwx/handlers/PermissionHandler.kt delete mode 100644 android/src/main/kotlin/com/jarvan/fluwx/handlers/WXAPiHandler.kt delete mode 100644 android/src/main/kotlin/com/jarvan/fluwx/io/ByteArrayToFile.kt delete mode 100644 android/src/main/kotlin/com/jarvan/fluwx/io/ImagesIO.kt delete mode 100644 android/src/main/kotlin/com/jarvan/fluwx/io/WeChatFiles.kt delete mode 100644 android/src/main/kotlin/com/jarvan/fluwx/utils/FluwxExtensions.kt delete mode 100644 android/src/main/kotlin/com/jarvan/fluwx/utils/WXApiUtils.java delete mode 100644 android/src/main/kotlin/com/jarvan/fluwx/wxapi/FluwxWXEntryActivity.kt delete mode 100644 android/src/main/res/values/styles.xml delete mode 100644 android/src/main/res/xml/fluwx_file_provider_paths.xml delete mode 100644 android/src/test/kotlin/com/jarvan/fluwx/FluwxPluginTest.kt delete mode 100644 ios/.gitignore delete mode 100644 ios/Assets/.gitkeep delete mode 100644 ios/Classes/FluwxDelegate.m delete mode 100644 ios/Classes/FluwxPlugin.m delete mode 100644 ios/Classes/FluwxStringUtil.h delete mode 100644 ios/Classes/FluwxStringUtil.m delete mode 100644 ios/Classes/NSStringWrapper.h delete mode 100644 ios/Classes/NSStringWrapper.m delete mode 100644 ios/Classes/ThumbnailHelper.h delete mode 100644 ios/Classes/ThumbnailHelper.m delete mode 100644 ios/Classes/public/FluwxDelegate.h delete mode 100644 ios/Classes/public/FluwxPlugin.h delete mode 100644 ios/Resources/PrivacyInfo.xcprivacy delete mode 100644 ios/fluwx.podspec delete mode 100644 ios/wechat_setup.rb delete mode 100644 ohos/.gitignore delete mode 100644 ohos/build-profile.json5 delete mode 100644 ohos/hvigorfile.ts delete mode 100644 ohos/index.ets delete mode 100644 ohos/local.properties delete mode 100644 ohos/oh-package.json5 delete mode 100644 ohos/src/main/ets/components/plugin/FluwxPlugin.ets delete mode 100644 ohos/src/main/ets/components/plugin/handlers/FluwxAuthHandler.ets delete mode 100644 ohos/src/main/ets/components/plugin/handlers/FluwxShareHandler.ets delete mode 100644 ohos/src/main/ets/components/plugin/handlers/WXAPiHandler.ets delete mode 100644 ohos/src/main/module.json5 diff --git a/android/.gitignore b/android/.gitignore deleted file mode 100644 index 161bdcda..00000000 --- a/android/.gitignore +++ /dev/null @@ -1,9 +0,0 @@ -*.iml -.gradle -/local.properties -/.idea/workspace.xml -/.idea/libraries -.DS_Store -/build -/captures -.cxx diff --git a/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java b/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java deleted file mode 100644 index 539ab022..00000000 --- a/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java +++ /dev/null @@ -1,19 +0,0 @@ -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) { - } -} diff --git a/android/build.gradle.copy b/android/build.gradle.copy deleted file mode 100644 index 087aa34a..00000000 --- a/android/build.gradle.copy +++ /dev/null @@ -1,161 +0,0 @@ -import org.yaml.snakeyaml.Yaml - -group 'com.jarvan.fluwx' -version '1.0-SNAPSHOT' - -Map projectYaml = loadPubspec() - -buildscript { - ext.kotlin_version = '2.1.0' - repositories { - google() - mavenCentral() - } - - dependencies { - classpath "com.android.tools.build:gradle:8.9.1" - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - classpath "org.yaml:snakeyaml:2.0" - } -} - -allprojects { - repositories { - google() - mavenCentral() - } -} - -apply plugin: 'com.android.library' -apply plugin: 'kotlin-android' -android { - if (project.android.hasProperty("namespace")) { - namespace 'com.jarvan.fluwx' - } - - compileSdk 34 - - compileOptions { - sourceCompatibility JavaVersion.VERSION_11 - targetCompatibility JavaVersion.VERSION_11 - } - - kotlinOptions { - jvmTarget = '11' - } - - sourceSets { - main.java.srcDirs += ['src/main/kotlin', "${buildDir}/generated/src/kotlin"] - test.java.srcDirs += 'src/test/kotlin' - } - - defaultConfig { - minSdkVersion 24 - consumerProguardFiles 'consumer-proguard-rules.txt' - } - - dependencies { - api 'com.tencent.mm.opensdk:wechat-sdk-android:6.8.34' - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2' - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.2' - implementation 'id.zelory:compressor:3.0.1' - implementation 'com.squareup.okhttp3:okhttp:5.2.1' - 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 - } - } - } -} - -Map loadPubspec() { - File pubspecFile - def yamlDir = rootProject.hasProperty('yamlDir') ? rootProject.ext.yamlDir : '' - def pubspecPath = rootProject.projectDir.parent + File.separator +yamlDir +"pubspec.yaml" - if(file(pubspecPath).exists()) { - pubspecFile = new File(pubspecPath) - } else { - def currentGradleFileDir = file(".").absolutePath // 当前 build.gradle 所在目录 - def parentDir = new File(currentGradleFileDir).getParentFile() // 获取父目录 - pubspecFile = new File(parentDir, "pubspec.yaml") // 构建 pubspec.yaml 路径 - } - - - InputStream input = new FileInputStream(pubspecFile) - Yaml yaml = new Yaml() - Map projectConfig = yaml.load(input) - - return projectConfig -} - - - -tasks.register("generateFluwxHelperFile") { - doFirst { - Map config = loadPubspec() - Map fluwx = (Map) config.get("fluwx") - String enableLogging = "false" - String interruptWeChatRequestByFluwx = "true" - String flutterActivity = "" - if (fluwx) { - Map android = (Map) fluwx.get("android") - if (android) { - def iwr = android.get("interrupt_wx_request") - if (iwr && iwr == "true" || iwr == "false") { - interruptWeChatRequestByFluwx = (String) - } - - def activity = android.get("flutter_activity") - if (activity) { - flutterActivity = (String) activity - } - } - - def logging = fluwx.get("debug_logging") - if ("${logging}" == "true" || "${logging}" == "false") { - enableLogging = "${logging}" - } - } - - generateFluwxConfigurations(interruptWeChatRequestByFluwx, flutterActivity, enableLogging) - } -} - -def generateFluwxConfigurations(String interruptWeChatRequestByFluwx, String flutterActivity, String enableLogging) { - File generateFolder = new File("${buildDir}/generated/src/kotlin/com/jarvan/fluwx") - - String template = "package com.jarvan.fluwx\n" + - "\n" + - "// auto generated\n" + - "internal object FluwxConfigurations {\n" + - " val flutterActivity: String = \"&&flutterActivity&&\"\n" + - " val enableLogging: Boolean = &&enableLogging&&\n" + - " val interruptWeChatRequestByFluwx: Boolean = &&interruptWeChatRequestByFluwx&&\n" + - "}" - if (!generateFolder.exists()) { - generateFolder.mkdirs() - } - - String source = template.replace("&&interruptWeChatRequestByFluwx&&", interruptWeChatRequestByFluwx) - .replace("&&flutterActivity&&", flutterActivity) - .replace("&&enableLogging&&", enableLogging) - file("${generateFolder.absolutePath}/FluwxConfigurations.kt").text = source -} - -//tasks.withType(JavaCompile) { javaCompile -> -// javaCompile.configure { -// dependsOn("generateFluwxHelperFile") -// } -//} -android.libraryVariants.configureEach { - it.registerGeneratedResFolders(project.files(new File("${buildDir}/generated/src/kotlin/com/jarvan/fluwx")).builtBy(generateFluwxHelperFile)) -} diff --git a/android/build.gradle.kts b/android/build.gradle.kts deleted file mode 100644 index 9c8b371a..00000000 --- a/android/build.gradle.kts +++ /dev/null @@ -1,164 +0,0 @@ -import org.yaml.snakeyaml.Yaml - -group = "com.jarvan.fluwx" -version = "1.0-SNAPSHOT" - -buildscript { - val kotlinVersion = "2.2.20" - repositories { - google() - mavenCentral() - } - - dependencies { - classpath("com.android.tools.build:gradle:8.11.1") - classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion") - classpath("org.yaml:snakeyaml:2.6") - } -} - -allprojects { - repositories { - google() - mavenCentral() - } -} - -plugins { - id("com.android.library") - id("kotlin-android") -} - - -android { - namespace = "com.jarvan.fluwx" - compileSdk = 34 - - compileOptions { - sourceCompatibility = JavaVersion.VERSION_17 - targetCompatibility = JavaVersion.VERSION_17 - } - - kotlinOptions { - jvmTarget = "17" - } - - sourceSets { - getByName("main") { - java.srcDirs("src/main/kotlin", "${layout.buildDirectory.get().asFile}/generated/src/kotlin") - } - getByName("test") { - java.srcDirs("src/test/kotlin") - } - } - - defaultConfig { - minSdk = 24 - consumerProguardFiles("consumer-proguard-rules.txt") - } - - dependencies { - api("com.tencent.mm.opensdk:wechat-sdk-android:6.8.34") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.2") - implementation("id.zelory:compressor:3.0.1") - implementation("com.squareup.okhttp3:okhttp:5.2.1") - testImplementation("org.jetbrains.kotlin:kotlin-test") - testImplementation("org.mockito:mockito-core:5.0.0") - } - - testOptions { - unitTests.all { - it.useJUnitPlatform() - it.testLogging { - events("passed", "skipped", "failed", "standardOut", "standardError") - outputs.upToDateWhen { false } - showStandardStreams = true - } - } - } -} - -fun Project.loadPubspec(): Map { - val yamlDir = if (rootProject.hasProperty("yamlDir")) rootProject.ext["yamlDir"] as String else "" - val pubspecPath = "${rootProject.projectDir.parent}${File.separator}${yamlDir}pubspec.yaml" - val pubspecFile = if (file(pubspecPath).exists()) { - File(pubspecPath) - } else { - val parentDir = File(file(".").absolutePath).parentFile - File(parentDir, "pubspec.yaml") - } - - @Suppress("UNCHECKED_CAST") - return Yaml().load>(pubspecFile.inputStream()) -} - -fun Project.generateFluwxConfigurations( - interruptWeChatRequestByFluwx: String, - flutterActivity: String, - enableLogging: String, -) { - val generateFolder = File("${layout.buildDirectory.get().asFile}/generated/src/kotlin/com/jarvan/fluwx") - val template = """ - package com.jarvan.fluwx - - // auto generated - internal object FluwxConfigurations { - val flutterActivity: String = "&&flutterActivity&&" - val enableLogging: Boolean = &&enableLogging&& - val interruptWeChatRequestByFluwx: Boolean = &&interruptWeChatRequestByFluwx&& - } - """.trimIndent() - - if (!generateFolder.exists()) { - generateFolder.mkdirs() - } - - val source = template - .replace("&&interruptWeChatRequestByFluwx&&", interruptWeChatRequestByFluwx) - .replace("&&flutterActivity&&", flutterActivity) - .replace("&&enableLogging&&", enableLogging) - File("${generateFolder.absolutePath}/FluwxConfigurations.kt").writeText(source) -} - -tasks.register("generateFluwxHelperFile") { - doFirst { - val config = loadPubspec() - @Suppress("UNCHECKED_CAST") - val fluwx = config["fluwx"] as? Map - var enableLogging = "false" - var interruptWeChatRequestByFluwx = "true" - var flutterActivity = "" - - if (fluwx != null) { - @Suppress("UNCHECKED_CAST") - val androidConfig = fluwx["android"] as? Map - if (androidConfig != null) { - val iwr = androidConfig["interrupt_wx_request"] - if (iwr != null && (iwr == "true" || iwr == "false")) { - interruptWeChatRequestByFluwx = iwr as String - } - val activity = androidConfig["flutter_activity"] - if (activity != null) { - flutterActivity = activity as String - } - } - - val logging = fluwx["debug_logging"] - if ("$logging" == "true" || "$logging" == "false") { - enableLogging = "$logging" - } - } - - generateFluwxConfigurations(interruptWeChatRequestByFluwx, flutterActivity, enableLogging) - } -} - -configure { - libraryVariants.configureEach { - registerGeneratedResFolders( - project.files(File("${layout.buildDirectory.get().asFile}/generated/src/kotlin/com/jarvan/fluwx")) - .builtBy(tasks.named("generateFluwxHelperFile")) - ) - } -} diff --git a/android/build.gradle.kts.bak b/android/build.gradle.kts.bak deleted file mode 100644 index 39ad2f59..00000000 --- a/android/build.gradle.kts.bak +++ /dev/null @@ -1,56 +0,0 @@ -group = "com.jarvan.fluwx" -version = "1.0-SNAPSHOT" - -plugins { - id("com.android.library") - kotlin("android") -} - -allprojects { - repositories { - google() - mavenCentral() - } -} - -android { - namespace = "com.jarvan.fluwx" - compileSdk = 31 - - - sourceSets { - val main by getting - main.java.srcDirs("src/main/kotlin") - val test by getting - test.java.srcDirs("src/test/kotlin") - } - - defaultConfig { - minSdk = 16 - consumerProguardFile("consumer-proguard-rules.txt") - } - - testOptions { - unitTests.all { - it.useJUnitPlatform() - it.testLogging { - events("passed", "skipped", "failed", "standardOut", "standardError") - showStandardStreams = true - it.outputs.upToDateWhen { - false - } - } - } - } -} - -dependencies { - api("com.tencent.mm.opensdk:wechat-sdk-android:6.8.24") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4") - implementation("id.zelory:compressor:3.0.1") - implementation("com.squareup.okhttp3:okhttp:4.10.0") - testImplementation("org.jetbrains.kotlin:kotlin-test") - testImplementation("org.mockito:mockito-core:5.0.0") -} - diff --git a/android/consumer-proguard-rules.txt b/android/consumer-proguard-rules.txt deleted file mode 100644 index f1897d89..00000000 --- a/android/consumer-proguard-rules.txt +++ /dev/null @@ -1,38 +0,0 @@ - -# 微信 - --keep class com.tencent.mm.opensdk.** {*;} --keep class com.tencent.wxop.** {*;} --keep class com.tencent.mm.sdk.** {*;} - -## Kotlin - -# ServiceLoader support --keepnames class kotlinx.coroutines.internal.MainDispatcherFactory {} --keepnames class kotlinx.coroutines.CoroutineExceptionHandler {} --keepnames class kotlinx.coroutines.android.AndroidExceptionPreHandler {} --keepnames class kotlinx.coroutines.android.AndroidDispatcherFactory {} - -# Most of volatile fields are updated with AFU and should not be mangled --keepclassmembernames class kotlinx.** { - volatile ; -} - -## OkHttp - -# JSR 305 annotations are for embedding nullability information. --dontwarn javax.annotation.** - -# A resource is loaded with a relative path so the package of this class must be preserved. --keeppackagenames okhttp3.internal.publicsuffix.* --adaptresourcefilenames okhttp3/internal/publicsuffix/PublicSuffixDatabase.gz - -# Animal Sniffer compileOnly dependency to ensure APIs are compatible with older versions of Java. --dontwarn org.codehaus.mojo.animal_sniffer.* - -# OkHttp platform used only on JVM and when Conscrypt and other security providers are available. --dontwarn okhttp3.internal.platform.** --dontwarn org.conscrypt.** --dontwarn org.bouncycastle.** --dontwarn org.openjsse.** - diff --git a/android/gen.gradle.kts b/android/gen.gradle.kts deleted file mode 100644 index 09009352..00000000 --- a/android/gen.gradle.kts +++ /dev/null @@ -1,32 +0,0 @@ -abstract class GenFluwxHelperTask : DefaultTask() { - @get:Incremental - @get:PathSensitive(PathSensitivity.NAME_ONLY) - @get:InputDirectory - abstract val inputDir: DirectoryProperty - - @get:OutputDirectory - abstract val outputDir: DirectoryProperty - - @get:Input - abstract val inputProperty: Property - - @TaskAction - fun execute(inputChanges: InputChanges) { - println( - if (inputChanges.isIncremental) "Executing incrementally" - else "Executing non-incrementally" - ) - - inputChanges.getFileChanges(inputDir).forEach { change -> - if (change.fileType == FileType.DIRECTORY) return@forEach - - println("${change.changeType}: ${change.normalizedPath}") - val targetFile = outputDir.file(change.normalizedPath).get().asFile -// if (change.changeType == ChangeType.REMOVED) { -// targetFile.delete() -// } else { -// targetFile.writeText(change.file.readText().reversed()) -// } - } - } -} \ No newline at end of file diff --git a/android/settings.gradle b/android/settings.gradle deleted file mode 100644 index 15566533..00000000 --- a/android/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -rootProject.name = 'fluwx' diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml deleted file mode 100644 index aae46b12..00000000 --- a/android/src/main/AndroidManifest.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/android/src/main/kotlin/com/jarvan/fluwx/FluwxFileProvider.kt b/android/src/main/kotlin/com/jarvan/fluwx/FluwxFileProvider.kt deleted file mode 100644 index c7a8d008..00000000 --- a/android/src/main/kotlin/com/jarvan/fluwx/FluwxFileProvider.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.jarvan.fluwx - -import androidx.core.content.FileProvider - -/*** - * Created by mo on 2020/5/13 - * 冷风如刀,以大地为砧板,视众生为鱼肉。 - * 万里飞雪,将穹苍作烘炉,熔万物为白银。 - **/ -class FluwxFileProvider: FileProvider() \ No newline at end of file diff --git a/android/src/main/kotlin/com/jarvan/fluwx/FluwxPlugin.kt b/android/src/main/kotlin/com/jarvan/fluwx/FluwxPlugin.kt deleted file mode 100644 index e43c4f51..00000000 --- a/android/src/main/kotlin/com/jarvan/fluwx/FluwxPlugin.kt +++ /dev/null @@ -1,541 +0,0 @@ -package com.jarvan.fluwx - -import android.content.Context -import android.content.Intent -import com.jarvan.fluwx.handlers.FluwxAuthHandler -import com.jarvan.fluwx.handlers.FluwxRequestHandler -import com.jarvan.fluwx.handlers.FluwxShareHandler -import com.jarvan.fluwx.handlers.FluwxShareHandlerEmbedding -import com.jarvan.fluwx.handlers.WXAPiHandler -import com.jarvan.fluwx.utils.WXApiUtils -import com.jarvan.fluwx.utils.readWeChatCallbackIntent -import com.tencent.mm.opensdk.modelbase.BaseReq -import com.tencent.mm.opensdk.modelbase.BaseResp -import com.tencent.mm.opensdk.modelbiz.ChooseCardFromWXCardPackage -import com.tencent.mm.opensdk.modelbiz.OpenRankList -import com.tencent.mm.opensdk.modelbiz.OpenWebview -import com.tencent.mm.opensdk.modelbiz.SubscribeMessage -import com.tencent.mm.opensdk.modelbiz.WXLaunchMiniProgram -import com.tencent.mm.opensdk.modelbiz.WXOpenBusinessView -import com.tencent.mm.opensdk.modelbiz.WXOpenBusinessWebview -import com.tencent.mm.opensdk.modelbiz.WXOpenCustomerServiceChat -import com.tencent.mm.opensdk.modelmsg.LaunchFromWX -import com.tencent.mm.opensdk.modelmsg.SendAuth -import com.tencent.mm.opensdk.modelmsg.SendMessageToWX -import com.tencent.mm.opensdk.modelmsg.ShowMessageFromWX -import com.tencent.mm.opensdk.modelpay.PayReq -import com.tencent.mm.opensdk.modelpay.PayResp -import com.tencent.mm.opensdk.openapi.IWXAPIEventHandler -import com.tencent.mm.opensdk.openapi.SendReqCallback -import com.tencent.mm.opensdk.utils.ILog -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.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 -import java.util.concurrent.atomic.AtomicBoolean - - -/** FluwxPlugin */ -class FluwxPlugin : FlutterPlugin, MethodCallHandler, ActivityAware, - PluginRegistry.NewIntentListener, IWXAPIEventHandler { - companion object { - // 主动获取的启动参数 - var extMsg: String? = null - } - - private val errStr = "errStr" - private val errCode = "errCode" - private val openId = "openId" - private val type = "type" - - private val weChatLogger = object : ILog { - - override fun d(p0: String?, p1: String?) { - logToFlutter(p0, p1) - } - - override fun i(p0: String?, p1: String?) { - logToFlutter(p0, p1) - } - - override fun e(p0: String?, p1: String?) { - logToFlutter(p0, p1) - } - - override fun v(p0: String?, p1: String?) { - logToFlutter(p0, p1) - } - - override fun w(p0: String?, p1: String?) { - logToFlutter(p0, p1) - } - } - private var shareHandler: FluwxShareHandler? = null - - private var authHandler: FluwxAuthHandler? = null - - private var fluwxChannel: MethodChannel? = null - - private var context: Context? = null - private val attemptToResumeMsgFromWxFlag = AtomicBoolean(false) - - private var activityPluginBinding: ActivityPluginBinding? = null - - override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { - val channel = MethodChannel(flutterPluginBinding.binaryMessenger, "com.jarvanmo/fluwx") - channel.setMethodCallHandler(this) - fluwxChannel = channel - context = flutterPluginBinding.applicationContext - authHandler = FluwxAuthHandler(channel) - shareHandler = FluwxShareHandlerEmbedding( - flutterPluginBinding.flutterAssets, flutterPluginBinding.applicationContext - ) - } - - override fun onMethodCall(call: MethodCall, result: Result) { - when { - call.method == "registerApp" -> { - WXAPiHandler.registerApp(call, result, context) - if (FluwxConfigurations.enableLogging) { - WXAPiHandler.wxApi?.setLogImpl(weChatLogger) - } - } - - call.method == "sendAuth" -> authHandler?.sendAuth(call, result) - call.method == "authByQRCode" -> authHandler?.authByQRCode(call, result) - call.method == "stopAuthByQRCode" -> authHandler?.stopAuthByQRCode(result) - call.method == "payWithFluwx" -> pay(call, result) - call.method == "payWithHongKongWallet" -> payWithHongKongWallet(call, result) - call.method == "launchMiniProgram" -> launchMiniProgram(call, result) - call.method == "subscribeMsg" -> subScribeMsg(call, result) - call.method == "autoDeduct" -> signAutoDeduct(call, result) - call.method == "autoDeductV2" -> autoDeductV2(call, result) - call.method == "openWXApp" -> openWXApp(result) - call.method.startsWith("share") -> shareHandler?.share(call, result) - call.method == "isWeChatInstalled" -> WXAPiHandler.checkWeChatInstallation(result) - call.method == "getExtMsg" -> getExtMsg(result) - call.method == "openWeChatCustomerServiceChat" -> openWeChatCustomerServiceChat( - call, result - ) - - call.method == "checkSupportOpenBusinessView" -> WXAPiHandler.checkSupportOpenBusinessView( - result - ) - - call.method == "openBusinessView" -> openBusinessView(call, result) - - call.method == "openWeChatInvoice" -> openWeChatInvoice(call, result) - call.method == "openUrl" -> openUrl(call, result) - call.method == "openRankList" -> openRankList(result) - call.method == "attemptToResumeMsgFromWx" -> attemptToResumeMsgFromWx(result) - call.method == "selfCheck" -> result.success(null) - else -> result.notImplemented() - } - } - - private fun attemptToResumeMsgFromWx(result: Result) { - if (attemptToResumeMsgFromWxFlag.compareAndSet(false, true)) { - activityPluginBinding?.activity?.intent?.let { - letWeChatHandleIntent(it) - } - - } - result.success(null) - } - - private fun openWeChatInvoice(call: MethodCall, result: Result) { - if (WXAPiHandler.wxApi == null) { - result.error("Unassigned WxApi", "please config wxapi first", null) - return - } else { - //android 只有ChooseCard, IOS直接有ChooseInvoice - val request = ChooseCardFromWXCardPackage.Req() - request.cardType = call.argument("cardType") - request.appId = call.argument("appId") - request.locationId = call.argument("locationId") - request.cardId = call.argument("cardId") - request.canMultiSelect = call.argument("canMultiSelect") - - request.timeStamp = System.currentTimeMillis().toString() - request.nonceStr = System.currentTimeMillis().toString() - request.signType = "SHA1" - request.cardSign = WXApiUtils.createSign( - request.appId, request.nonceStr, request.timeStamp, request.cardType - ) - val done = WXAPiHandler.wxApi?.sendReq(request) - result.success(done) - } - } - - override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) { - shareHandler?.onDestroy() - authHandler?.removeAllListeners() - activityPluginBinding = null - } - - override fun onDetachedFromActivity() { - } - - override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) { - onAttachedToActivity(binding) - } - - override fun onAttachedToActivity(binding: ActivityPluginBinding) { -// WXAPiHandler.setContext(binding.activity.applicationContext) - activityPluginBinding = binding - binding.addOnNewIntentListener(this) - } - - override fun onDetachedFromActivityForConfigChanges() { - } - - - private fun getExtMsg(result: Result) { - result.success(extMsg) - extMsg = null - } - - private fun pay(call: MethodCall, result: Result) { - - if (WXAPiHandler.wxApi == null) { - result.error("Unassigned WxApi", "please config wxapi first", null) - return - } else { - // 将该app注册到微信 - val request = PayReq() - request.appId = call.argument("appId") - request.partnerId = call.argument("partnerId") - request.prepayId = call.argument("prepayId") - request.packageValue = call.argument("packageValue") - request.nonceStr = call.argument("nonceStr") - request.timeStamp = call.argument("timeStamp").toString() - request.sign = call.argument("sign") - request.signType = call.argument("signType") - request.extData = call.argument("extData") - val done = WXAPiHandler.wxApi?.sendReq(request) - result.success(done) - } - } - - private fun payWithHongKongWallet(call: MethodCall, result: Result) { - val prepayId = call.argument("prepayId") ?: "" - val request = WXOpenBusinessWebview.Req() - request.businessType = 1 - request.queryInfo = hashMapOf( - "token" to prepayId - ) - result.success(WXAPiHandler.wxApi?.sendReq(request)) - } - - private fun openWeChatCustomerServiceChat(call: MethodCall, result: Result) { - val url = call.argument("url") ?: "" - val corpId = call.argument("corpId") ?: "" - val request = WXOpenCustomerServiceChat.Req() - request.corpId = corpId // 企业ID - - request.url = url - result.success(WXAPiHandler.wxApi?.sendReq(request)) - } - - private fun openBusinessView(call: MethodCall, result: Result) { - val request = WXOpenBusinessView.Req() - request.businessType = call.argument("businessType") ?: "" - request.query = call.argument("query") ?: "" - request.extInfo = "{\"miniProgramType\": 0}" - result.success(WXAPiHandler.wxApi?.sendReq(request)) - } - - private fun signAutoDeduct(call: MethodCall, result: Result) { - val appId: String = call.argument("appid") ?: "" - val mchId = call.argument("mch_id") ?: "" - val planId = call.argument("plan_id") ?: "" - val contractCode = call.argument("contract_code") ?: "" - val requestSerial = call.argument("request_serial") ?: "" - val contractDisplayAccount = call.argument("contract_display_account") ?: "" - val notifyUrl = call.argument("notify_url") ?: "" - val version = call.argument("version") ?: "" - val sign = call.argument("sign") ?: "" - val timestamp = call.argument("timestamp") ?: "" - val returnApp = call.argument("return_app") ?: "" - val businessType = call.argument("businessType") ?: 12 - - val req = WXOpenBusinessWebview.Req() - req.businessType = businessType - req.queryInfo = hashMapOf( - "appid" to appId, - "mch_id" to mchId, - "plan_id" to planId, - "contract_code" to contractCode, - "request_serial" to requestSerial, - "contract_display_account" to contractDisplayAccount, - "notify_url" to notifyUrl, - "version" to version, - "sign" to sign, - "timestamp" to timestamp, - "return_app" to returnApp - ) - result.success(WXAPiHandler.wxApi?.sendReq(req)) - } - - private fun autoDeductV2(call: MethodCall, result: Result) { - val businessType = call.argument("businessType") ?: 12 - - val req = WXOpenBusinessWebview.Req() - req.businessType = businessType - req.queryInfo = call.argument>("queryInfo") ?: hashMapOf() - - result.success(WXAPiHandler.wxApi?.sendReq(req)) - } - - private fun subScribeMsg(call: MethodCall, result: Result) { - val appId = call.argument("appId") - val scene = call.argument("scene") - val templateId = call.argument("templateId") - val reserved = call.argument("reserved") - - val req = SubscribeMessage.Req() - req.openId = appId - req.scene = scene!! - req.reserved = reserved - req.templateID = templateId - val b = WXAPiHandler.wxApi?.sendReq(req) - result.success(b) - } - - private fun launchMiniProgram(call: MethodCall, result: Result) { - val req = WXLaunchMiniProgram.Req() - req.userName = call.argument("userName") // 填小程序原始id - req.path = call.argument("path") ?: "" //拉起小程序页面的可带参路径,不填默认拉起小程序首页 - val type = call.argument("miniProgramType") ?: 0 - req.miniprogramType = when (type) { - 1 -> WXLaunchMiniProgram.Req.MINIPROGRAM_TYPE_TEST - 2 -> WXLaunchMiniProgram.Req.MINIPROGRAM_TYPE_PREVIEW - else -> WXLaunchMiniProgram.Req.MINIPTOGRAM_TYPE_RELEASE - }// 可选打开 开发版,体验版和正式版 - val done = WXAPiHandler.wxApi?.sendReq(req) - result.success(done) - } - - private fun openWXApp(result: Result) = result.success(WXAPiHandler.wxApi?.openWXApp()) - - private fun openUrl(call: MethodCall, result: Result) { - val req = OpenWebview.Req() - req.url = call.argument("url") - WXAPiHandler.wxApi?.sendReq(req, SendReqCallback { - result.success(it) - }) ?: kotlin.run { - result.success(false) - } - } - - private fun openRankList(result: Result) { - val req = OpenRankList.Req() - WXAPiHandler.wxApi?.sendReq(req, SendReqCallback { - result.success(it) - }) ?: kotlin.run { - result.success(false) - } - } - - override fun onNewIntent(intent: Intent): Boolean { - return letWeChatHandleIntent(intent) - } - - private fun letWeChatHandleIntent(intent: Intent): Boolean = - intent.readWeChatCallbackIntent()?.let { - WXAPiHandler.wxApi?.handleIntent(it, this) ?: false - } ?: run { - false - } - - override fun onReq(req: BaseReq?) { - activityPluginBinding?.activity?.let { activity -> - req?.let { - if (FluwxConfigurations.interruptWeChatRequestByFluwx) { - when (req) { - is ShowMessageFromWX.Req -> handleShowMessageFromWX(req) - is LaunchFromWX.Req -> handleLaunchFromWX(req) - else -> {} - } - } else { - FluwxRequestHandler.customOnReqDelegate?.invoke(req, activity) - } - } - } - } - - - private fun handleShowMessageFromWX(req: ShowMessageFromWX.Req) { - val result = mapOf( - "extMsg" to req.message.messageExt, - "messageAction" to req.message.messageAction, - "description" to req.message.description, - "lang" to req.lang, - "description" to req.country, - ) - - extMsg = req.message.messageExt - fluwxChannel?.invokeMethod("onWXShowMessageFromWX", result) - } - - private fun handleLaunchFromWX(req: LaunchFromWX.Req) { - val result = mapOf( - "extMsg" to req.messageExt, - "messageAction" to req.messageAction, - "lang" to req.lang, - "country" to req.country, - ) - extMsg = req.messageExt - - fluwxChannel?.invokeMethod("onWXLaunchFromWX", result) - } - - override fun onResp(response: BaseResp?) { - when (response) { - is SendAuth.Resp -> handleAuthResponse(response) - is SendMessageToWX.Resp -> handleSendMessageResp(response) - is PayResp -> handlePayResp(response) - is WXLaunchMiniProgram.Resp -> handleLaunchMiniProgramResponse(response) - is SubscribeMessage.Resp -> handleSubscribeMessage(response) - is WXOpenBusinessWebview.Resp -> handlerWXOpenBusinessWebviewResponse(response) - is WXOpenCustomerServiceChat.Resp -> handlerWXOpenCustomerServiceChatResponse(response) - is WXOpenBusinessView.Resp -> handleWXOpenBusinessView(response) - is ChooseCardFromWXCardPackage.Resp -> handleWXOpenInvoiceResponse(response) - else -> {} - } - } - - private fun handleWXOpenInvoiceResponse(response: ChooseCardFromWXCardPackage.Resp) { - val result = mapOf( - "cardItemList" to response.cardItemList, - "transaction" to response.transaction, - "openid" to response.openId, - errStr to response.errStr, - type to response.type, - errCode to response.errCode - ) - - fluwxChannel?.invokeMethod("onOpenWechatInvoiceResponse", result) - } - - private fun handleWXOpenBusinessView(response: WXOpenBusinessView.Resp) { - val result = mapOf( - "openid" to response.openId, - "extMsg" to response.extMsg, - "businessType" to response.businessType, - errStr to response.errStr, - type to response.type, - errCode to response.errCode - ) - - fluwxChannel?.invokeMethod("onOpenBusinessViewResponse", result) - } - - private fun handleSubscribeMessage(response: SubscribeMessage.Resp) { - val result = mapOf( - "openid" to response.openId, - "templateId" to response.templateID, - "action" to response.action, - "reserved" to response.reserved, - "scene" to response.scene, - type to response.type - ) - - fluwxChannel?.invokeMethod("onSubscribeMsgResp", result) - } - - private fun handleLaunchMiniProgramResponse(response: WXLaunchMiniProgram.Resp) { - val result = mutableMapOf( - errStr to response.errStr, - type to response.type, - errCode to response.errCode, - openId to response.openId - ) - - response.extMsg?.let { - result["extMsg"] = response.extMsg - } - - fluwxChannel?.invokeMethod("onLaunchMiniProgramResponse", result) - } - - private fun handlePayResp(response: PayResp) { - val result = mapOf( - "prepayId" to response.prepayId, - "returnKey" to response.returnKey, - "extData" to response.extData, - errStr to response.errStr, - type to response.type, - errCode to response.errCode - ) - fluwxChannel?.invokeMethod("onPayResponse", result) - } - - private fun handleSendMessageResp(response: SendMessageToWX.Resp) { - val result = mapOf( - errStr to response.errStr, - type to response.type, - errCode to response.errCode, - openId to response.openId - ) - - fluwxChannel?.invokeMethod("onShareResponse", result) - } - - private fun handleAuthResponse(response: SendAuth.Resp) { - val result = mapOf( - errCode to response.errCode, - "code" to response.code, - "state" to response.state, - "lang" to response.lang, - "country" to response.country, - errStr to response.errStr, - openId to response.openId, - "url" to response.url, - type to response.type - ) - - fluwxChannel?.invokeMethod("onAuthResponse", result) - } - - - private fun handlerWXOpenBusinessWebviewResponse(response: WXOpenBusinessWebview.Resp) { - val result = mapOf( - errCode to response.errCode, - "businessType" to response.businessType, - "resultInfo" to response.resultInfo, - errStr to response.errStr, - openId to response.openId, - type to response.type - ) - - fluwxChannel?.invokeMethod("onWXOpenBusinessWebviewResponse", result) - } - - private fun handlerWXOpenCustomerServiceChatResponse(response: WXOpenCustomerServiceChat.Resp) { - val result = mapOf( - errCode to response.errCode, - errStr to response.errStr, - openId to response.openId, - type to response.type - ) - - fluwxChannel?.invokeMethod("onWXOpenCustomerServiceChatResponse", result) - } - - private fun logToFlutter(tag: String?, message: String?) { - activityPluginBinding?.activity?.runOnUiThread { - fluwxChannel?.invokeMethod( - "wechatLog", mapOf( - "detail" to "$tag : $message" - ) - ) - } - } - - -} diff --git a/android/src/main/kotlin/com/jarvan/fluwx/handlers/FluwxAuthHandler.kt b/android/src/main/kotlin/com/jarvan/fluwx/handlers/FluwxAuthHandler.kt deleted file mode 100644 index 2e70f231..00000000 --- a/android/src/main/kotlin/com/jarvan/fluwx/handlers/FluwxAuthHandler.kt +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2020 The OpenFlutter Organization - * - * 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. - */ -package com.jarvan.fluwx.handlers - -import com.tencent.mm.opensdk.diffdev.DiffDevOAuthFactory -import com.tencent.mm.opensdk.diffdev.OAuthErrCode -import com.tencent.mm.opensdk.diffdev.OAuthListener -import com.tencent.mm.opensdk.modelmsg.SendAuth -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel - -internal class FluwxAuthHandler(private val methodChannel: MethodChannel) { - // private DiffDevOAuthFactory.getDiffDevOAuth() - private val qrCodeAuth by lazy { - DiffDevOAuthFactory.getDiffDevOAuth() - } - - private val qrCodeAuthListener by lazy { - object : OAuthListener { - override fun onAuthFinish(p0: OAuthErrCode, authCode: String?) { - methodChannel.invokeMethod("onAuthByQRCodeFinished", mapOf( - "errCode" to p0.code, - "authCode" to authCode - )) - } - - override fun onAuthGotQrcode(p0: String?, p1: ByteArray) { - methodChannel.invokeMethod("onAuthGotQRCode", mapOf("errCode" to 0, "qrCode" to p1)) - } - - override fun onQrcodeScanned() { - methodChannel.invokeMethod("onQRCodeScanned", mapOf("errCode" to 0)) - } - - } - } - - - fun sendAuth(call: MethodCall, result: MethodChannel.Result) { - val req = SendAuth.Req() - req.scope = call.argument("scope") - req.state = call.argument("state") - val openId = call.argument("openId") - if (!openId.isNullOrBlank()) { - req.openId = call.argument("openId") - } - req.nonAutomatic = call.argument("nonAutomatic") ?: false - result.success(WXAPiHandler.wxApi?.sendReq(req)) - } - - - fun authByQRCode(call: MethodCall, result: MethodChannel.Result) { - val appId = call.argument("appId") ?: "" - val scope = call.argument("scope") ?: "" - val nonceStr = call.argument("nonceStr") ?: "" - val timeStamp = call.argument("timeStamp") ?: "" - val signature = call.argument("signature") ?: "" -// val schemeData = call.argument("schemeData")?:"" - - result.success(qrCodeAuth.auth(appId, scope, nonceStr, timeStamp, signature, qrCodeAuthListener)) - } - - fun stopAuthByQRCode(result: MethodChannel.Result) { - result.success(qrCodeAuth.stopAuth()) - } - - fun removeAllListeners() { - qrCodeAuth.removeAllListeners() - } -} \ No newline at end of file diff --git a/android/src/main/kotlin/com/jarvan/fluwx/handlers/FluwxRequestHandler.kt b/android/src/main/kotlin/com/jarvan/fluwx/handlers/FluwxRequestHandler.kt deleted file mode 100644 index 7968e122..00000000 --- a/android/src/main/kotlin/com/jarvan/fluwx/handlers/FluwxRequestHandler.kt +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2020 The OpenFlutter Organization - * - * 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. - */ -package com.jarvan.fluwx.handlers - -import android.app.Activity -import com.tencent.mm.opensdk.modelbase.BaseReq - - -object FluwxRequestHandler { - - var customOnReqDelegate: ((baseReq: BaseReq, activity: Activity) -> Unit)? = null -} \ No newline at end of file diff --git a/android/src/main/kotlin/com/jarvan/fluwx/handlers/FluwxShareHandler.kt b/android/src/main/kotlin/com/jarvan/fluwx/handlers/FluwxShareHandler.kt deleted file mode 100644 index 0df3632c..00000000 --- a/android/src/main/kotlin/com/jarvan/fluwx/handlers/FluwxShareHandler.kt +++ /dev/null @@ -1,400 +0,0 @@ -package com.jarvan.fluwx.handlers - -import android.content.Context -import android.content.Intent -import android.content.res.AssetFileDescriptor -import android.net.Uri -import androidx.core.content.FileProvider -import com.jarvan.fluwx.io.* -import com.tencent.mm.opensdk.modelbase.BaseReq -import com.tencent.mm.opensdk.modelmsg.* -import io.flutter.embedding.engine.plugins.FlutterPlugin -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel -import kotlinx.coroutines.* -import java.io.File -import java.io.IOException -import java.util.* -import kotlin.coroutines.CoroutineContext -import android.os.Build -import io.flutter.plugin.common.MethodChannel.Result - - -/*** - * Created by mo on 2020/3/6 - * 冷风如刀,以大地为砧板,视众生为鱼肉。 - * 万里飞雪,将穹苍作烘炉,熔万物为白银。 - **/ -internal class FluwxShareHandlerEmbedding( - private val flutterAssets: FlutterPlugin.FlutterAssets, - override val context: Context -) : FluwxShareHandler { - override val assetFileDescriptor: (String) -> AssetFileDescriptor = { - val uri = Uri.parse(it) - val packageName = uri.getQueryParameter("package") - val subPath = if (packageName.isNullOrBlank()) { - flutterAssets.getAssetFilePathBySubpath(uri.path.orEmpty()) - } else { - flutterAssets.getAssetFilePathBySubpath(uri.path.orEmpty(), packageName) - } - context.assets.openFd(subPath) - } - - override val job: Job = Job() - -} - -internal interface FluwxShareHandler : CoroutineScope { - companion object { - const val SHARE_IMAGE_THUMB_LENGTH = 32 * 1024 - const val SHARE_MINI_PROGRAM_THUMB_LENGTH = 120 * 1024 - private const val keyTitle = "title" - private const val keyThumbnail = "thumbnail" - private const val keyDescription = "description" - } - - fun share(call: MethodCall, result: MethodChannel.Result) { - if (WXAPiHandler.wxApi == null) { - result.error("Unassigned WxApi", "please config wxapi first", null) - return - } - - when (call.method) { - "shareText" -> shareText(call, result) - "shareMiniProgram" -> shareMiniProgram(call, result) - "shareImage" -> shareImage(call, result) - "shareMusic" -> shareMusic(call, result) - "shareVideo" -> shareVideo(call, result) - "shareWebPage" -> shareWebPage(call, result) - "shareFile" -> shareFile(call, result) - "shareEmoji" -> shareEmoji(call, result) - else -> { - result.notImplemented() - } - } - } - - private fun shareText(call: MethodCall, result: MethodChannel.Result) { - val textObj = WXTextObject(call.argument("source")) - val msg = WXMediaMessage() - msg.mediaObject = textObj - val req = SendMessageToWX.Req() - setCommonArguments(call, req, msg) - req.message = msg - result.success(WXAPiHandler.wxApi?.sendReq(req)) - } - - - private fun shareMiniProgram(call: MethodCall, result: MethodChannel.Result) { - val miniProgramObj = WXMiniProgramObject() - miniProgramObj.webpageUrl = call.argument("webPageUrl") // 兼容低版本的网页链接 - miniProgramObj.miniprogramType = call.argument("miniProgramType") ?: 0// 正式版:0,测试版:1,体验版:2 - miniProgramObj.userName = call.argument("userName") // 小程序原始id - miniProgramObj.path = call.argument("path") //小程序页面路径 - miniProgramObj.withShareTicket = call.argument("withShareTicket") ?: true - val msg = WXMediaMessage(miniProgramObj) - msg.title = call.argument(keyTitle) // 小程序消息title - msg.description = call.argument(keyDescription) // 小程序消息desc - - launch { - val req = SendMessageToWX.Req() - setCommonArguments(call, req, msg) - req.message = msg - sendRequestInMain(result, req) - } - } - - private fun shareImage(call: MethodCall, result: MethodChannel.Result) { - launch { - val map: Map = call.argument("source") ?: mapOf() - - val imgHash = call.argument("imgDataHash") - val localImagePath = map["localImagePath"] as? String - val imageObject = localImagePath?.let { - WXImageObject().apply { - if (supportFileProvider && targetHigherThanN) { - if (localImagePath.startsWith("content://")) { - imagePath = localImagePath - } else { - val tempFile = File(localImagePath) - val ecd = context.externalCacheDir ?: return@apply - val desPath = - ecd.absolutePath + File.separator + cachePathName - if (tempFile.exists()) { - val target = if (isFileInDirectory( - file = tempFile, - directory = File(desPath) - ) - ) { - tempFile - } else { - withContext(Dispatchers.IO) { - copyFile(tempFile.absolutePath, desPath) - } - } - - imagePath = getFileContentUri(target) - } - } - } else { - imagePath = localImagePath - } - - imgDataHash = imgHash - } - } ?: run { - WXImageObject().apply { - val uint8List = map["uint8List"] as? ByteArray - uint8List?.let { - imageData = it - imgDataHash = imgHash - } - } - } - - - val msg = WXMediaMessage() - msg.mediaObject = imageObject - - msg.description = call.argument(keyDescription) - - val req = SendMessageToWX.Req() - setCommonArguments(call, req, msg) - req.message = msg - - sendRequestInMain(result, req) - } - } - - - private fun shareMusic(call: MethodCall, result: MethodChannel.Result) { - val music = WXMusicObject() - val musicUrl: String? = call.argument("musicUrl") - val musicLowBandUrl: String? = call.argument("musicLowBandUrl") - if (musicUrl != null && musicUrl.isNotBlank()) { - music.musicUrl = musicUrl - music.musicDataUrl = call.argument("musicDataUrl") - } else { - music.musicLowBandUrl = musicLowBandUrl - music.musicLowBandDataUrl = call.argument("musicLowBandDataUrl") - } - val msg = WXMediaMessage() - msg.mediaObject = music - msg.description = call.argument(keyDescription) - - launch { - val req = SendMessageToWX.Req() - setCommonArguments(call, req, msg) - req.message = msg - sendRequestInMain(result, req) - } - } - - private fun shareVideo(call: MethodCall, result: MethodChannel.Result) { - val video = WXVideoObject() - val videoUrl: String? = call.argument("videoUrl") - val videoLowBandUrl: String? = call.argument("videoLowBandUrl") - if (videoUrl != null && videoUrl.isNotBlank()) { - video.videoUrl = videoUrl - } else { - video.videoLowBandUrl = videoLowBandUrl - } - val msg = WXMediaMessage() - msg.mediaObject = video - msg.description = call.argument(keyDescription) - - launch { - val req = SendMessageToWX.Req() - setCommonArguments(call, req, msg) - req.message = msg - - sendRequestInMain(result, req) - } - } - - private fun shareWebPage(call: MethodCall, result: MethodChannel.Result) { - val webPage = WXWebpageObject() - webPage.webpageUrl = call.argument("webPage") - val msg = WXMediaMessage() - - msg.mediaObject = webPage - msg.description = call.argument(keyDescription) - - launch { - val req = SendMessageToWX.Req() - setCommonArguments(call, req, msg) - req.message = msg - sendRequestInMain(result, req) - } - } - - private fun shareFile(call: MethodCall, result: MethodChannel.Result) { - launch { - - val wxFileObject = WXFileObject() -// val filePath: String? = call.argument("filePath") -// wxFileObject.filePath = filePath - - val msg = WXMediaMessage() - msg.mediaObject = wxFileObject - msg.description = call.argument("description") - - val map: Map = call.argument("source") ?: mapOf() - val sourceFile = WeChatFile.createWeChatFile(map, assetFileDescriptor) - - val sourceByteArray = sourceFile.readByteArray() - - wxFileObject.apply { - if (supportFileProvider && targetHigherThanN) { - setFilePath( - getFileContentUri( - sourceByteArray.toCacheFile( - context, - sourceFile.suffix - ) - ) - ) - } else { - filePath = sourceByteArray.toExternalCacheFile( - context, - sourceFile.suffix - )?.absolutePath - } - } - - val req = SendMessageToWX.Req() - setCommonArguments(call, req, msg) - req.message = msg - sendRequestInMain(result, req) - } - } - - private fun shareEmoji(call: MethodCall, result: Result) { - - val scene = call.argument("scene") ?: 0 - val title = call.argument("title") - val desc = call.argument("description") - val thumbData = call.argument("thumbData") - - val emojiMap = call.argument>("source") - ?: run { result.error("ARG", "emoji is null", null); return } - - val emojiObj = WXEmojiObject().apply { - when { - emojiMap["uint8List"] != null -> emojiData = emojiMap["uint8List"] as ByteArray - emojiMap["path"] != null -> emojiPath = ensurePublicPath(emojiMap["path"] as String) - else -> { result.error("ARG", "gif source missing", null); return } - } - } - - val msg = WXMediaMessage(emojiObj).apply { - this.thumbData = thumbData - this.title = title - this.description = desc - } - - val req = SendMessageToWX.Req().apply { - transaction = "emoji${System.currentTimeMillis()}" - message = msg - this.scene = scene - } - - result.success(WXAPiHandler.wxApi?.sendReq(req)) - } - - private suspend fun sendRequestInMain(result: MethodChannel.Result, request: BaseReq) = - withContext(Dispatchers.Main) { - result.success(WXAPiHandler.wxApi?.sendReq(request)) - } - - private suspend fun compressThumbnail(ioIml: ImagesIO, length: Int) = - ioIml.compressedByteArray(context, length) - - // SESSION, TIMELINE, FAVORITE - private fun setCommonArguments( - call: MethodCall, - req: SendMessageToWX.Req, - msg: WXMediaMessage - ) { - msg.messageAction = call.argument("messageAction") - call.argument("msgSignature")?.let { - msg.msgSignature = it - } - call.argument("thumbData")?.let { - msg.thumbData = it - } - - call.argument("thumbDataHash")?.let { - msg.thumbDataHash = it - } - - msg.messageExt = call.argument("messageExt") - msg.mediaTagName = call.argument("mediaTagName") - msg.title = call.argument(keyTitle) - msg.description = call.argument(keyDescription) - req.transaction = UUID.randomUUID().toString().replace("-", "") - val sceneIndex = call.argument("scene") - req.scene = when (sceneIndex) { - 0 -> SendMessageToWX.Req.WXSceneSession - 1 -> SendMessageToWX.Req.WXSceneTimeline - 2 -> SendMessageToWX.Req.WXSceneFavorite - else -> SendMessageToWX.Req.WXSceneSession - } - } - - private fun getFileContentUri(file: File?): String? { - if (file == null || !file.exists()) - return null - - val contentUri = FileProvider.getUriForFile( - context, - "${context.packageName}.fluwxprovider", // 要与`AndroidManifest.xml`里配置的`authorities`一致,假设你的应用包名为com.example.app - file - ) - - // 授权给微信访问路径 - context.grantUriPermission( - "com.tencent.mm", // 这里填微信包名 - contentUri, Intent.FLAG_GRANT_READ_URI_PERMISSION - ) - - return contentUri.toString() // contentUri.toString() 即是以"content://"开头的用于共享的路径 - - } - - private fun loadBytesFromFlutterAsset(assetKey: String): ByteArray = - context.assets.open(assetKey.removePrefix("flutterassets/")).use { it.readBytes() } - - private fun ensurePublicPath(original: String): String { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) return original - val src = File(original) - val dst = File(context.externalCacheDir, src.name) - if (!dst.exists()) src.copyTo(dst, overwrite = true) - return dst.path - } - - private val supportFileProvider: Boolean - get() = (WXAPiHandler.wxApi?.wxAppSupportAPI ?: 0) >= 0x27000D00 - private val targetHigherThanN: Boolean get() = android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N - - val context: Context - - val assetFileDescriptor: (String) -> AssetFileDescriptor - - override val coroutineContext: CoroutineContext - get() = Dispatchers.Main + job - - val job: Job - - fun onDestroy() = job.cancel() -} - -private fun isFileInDirectory(file: File, directory: File): Boolean { - return try { - val filePath = file.canonicalPath - val dirPath = directory.canonicalPath - filePath.startsWith(dirPath) - } catch (e: IOException) { - false - } -} \ No newline at end of file diff --git a/android/src/main/kotlin/com/jarvan/fluwx/handlers/PermissionHandler.kt b/android/src/main/kotlin/com/jarvan/fluwx/handlers/PermissionHandler.kt deleted file mode 100644 index e359bfe9..00000000 --- a/android/src/main/kotlin/com/jarvan/fluwx/handlers/PermissionHandler.kt +++ /dev/null @@ -1,39 +0,0 @@ -package com.jarvan.fluwx.handlers - -import android.Manifest -import android.app.Activity -import android.app.Fragment -import android.os.Build - -/*** - * Created by mo on 2020/3/27 - * 冷风如刀,以大地为砧板,视众生为鱼肉。 - * 万里飞雪,将穹苍作烘炉,熔万物为白银。 - **/ -class PermissionHandler(private val activity: Activity?) { - private val tag = "Fragment_TAG" - private val fragment: Fragment = Fragment() - - fun requestStoragePermission() { - if (oldFragment != null) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - oldFragment?.requestPermissions(arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), 12121) - } - } else { - activity?.run { - val ft = fragmentManager.beginTransaction() - ft.add(fragment, tag) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - ft.commitNow() - } else { - ft.commit() - } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - fragment.requestPermissions(arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), 12121) - } - } - } - } - - private val oldFragment get() = activity?.fragmentManager?.findFragmentByTag(tag) -} \ No newline at end of file diff --git a/android/src/main/kotlin/com/jarvan/fluwx/handlers/WXAPiHandler.kt b/android/src/main/kotlin/com/jarvan/fluwx/handlers/WXAPiHandler.kt deleted file mode 100644 index 700e29bd..00000000 --- a/android/src/main/kotlin/com/jarvan/fluwx/handlers/WXAPiHandler.kt +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (c) 2020. OpenFlutter Project - * - * Licensed to the Apache Software Foundation (ASF) under one or more contributor - * license agreements. See the NOTICE file distributed with this work for - * additional information regarding copyright ownership. The ASF licenses this - * file to you 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. - */ -package com.jarvan.fluwx.handlers - -import android.content.Context -import android.content.pm.PackageManager -import android.util.Log -import com.jarvan.fluwx.FluwxPlugin -import com.tencent.mm.opensdk.constants.Build -import com.tencent.mm.opensdk.openapi.IWXAPI -import com.tencent.mm.opensdk.openapi.WXAPIFactory -import com.tencent.mm.opensdk.utils.ILog -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel - -object WXAPiHandler { - - var wxApi: IWXAPI? = null - -// private var context: Context? = null - - private var registered: Boolean = false - - val wxApiRegistered get() = registered - - //是否为冷启动 - var coolBoot: Boolean = false - - fun setupWxApi(appId: String, context: Context, force: Boolean = true): Boolean { - if (force || !registered) { -// setContext(context) - registerWxAPIInternal(appId, context) - } - return registered - } -// -// fun setContext(context: Context?) { -// WXAPiHandler.context = context -// } - - fun registerApp(call: MethodCall, result: MethodChannel.Result, context: Context?) { - - if (call.argument("android") == false) { - return - } - - if (wxApi != null) { - result.success(true) - return - } - - val appId: String? = call.argument("appId") - if (appId.isNullOrBlank()) { - result.error("invalid app id", "are you sure your app id is correct ?", appId) - return - } - - context?.let { - registerWxAPIInternal(appId, it) - } - result.success(registered) - } - - fun checkWeChatInstallation(result: MethodChannel.Result) { - if (wxApi == null) { - result.error("Unassigned WxApi", "please config wxapi first", null) - return - } else { - result.success(wxApi?.isWXAppInstalled) - } - } - - fun checkSupportOpenBusinessView(result: MethodChannel.Result) { - when { - wxApi == null -> { - result.error("Unassigned WxApi", "please config wxapi first", null) - } - - wxApi?.isWXAppInstalled != true -> { - result.error("WeChat Not Installed", "Please install the WeChat first", null) - } - - (wxApi?.wxAppSupportAPI ?: 0) < Build.OPEN_BUSINESS_VIEW_SDK_INT -> { - result.error("WeChat Not Supported", "Please upgrade the WeChat version", null) - } - - else -> { - result.success(true) - } - } - } - - private fun registerWxAPIInternal(appId: String, context: Context) { - val api = WXAPIFactory.createWXAPI(context.applicationContext, appId) - registered = api.registerApp(appId) - wxApi = api - } - -} - - diff --git a/android/src/main/kotlin/com/jarvan/fluwx/io/ByteArrayToFile.kt b/android/src/main/kotlin/com/jarvan/fluwx/io/ByteArrayToFile.kt deleted file mode 100644 index bbe8a474..00000000 --- a/android/src/main/kotlin/com/jarvan/fluwx/io/ByteArrayToFile.kt +++ /dev/null @@ -1,83 +0,0 @@ -package com.jarvan.fluwx.io - -import android.content.Context -import android.util.Log -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import okio.* -import java.io.* -import java.io.IOException -import java.util.* - -/*** - * Created by mo on 2020/5/13 - * 冷风如刀,以大地为砧板,视众生为鱼肉。 - * 万里飞雪,将穹苍作烘炉,熔万物为白银。 - **/ - -internal const val cachePathName = "fluwxSharedData" - -internal suspend fun ByteArray.toExternalCacheFile(context: Context, suffix: String): File? { - var file: File? = null - val externalFile = context.externalCacheDir ?: return file - val dir = File(externalFile.absolutePath + File.separator + cachePathName).apply { - if (!exists()) { - mkdirs() - } - } - file = File(dir.absolutePath + File.separator + UUID.randomUUID().toString() + suffix) - return saveToLocal(this, file) -} - -internal suspend fun ByteArray.toCacheFile(context: Context, suffix: String): File? { - var file: File? = null - val externalFile = context.cacheDir ?: return file - val dir = File(externalFile.absolutePath + File.separator + cachePathName).apply { - if (!exists()) { - mkdirs() - } - } - file = File(dir.absolutePath + File.separator + UUID.randomUUID().toString() + suffix) - return saveToLocal(this, file) -} - -private suspend fun saveToLocal(byteArray: ByteArray, file: File): File? { - return withContext(Dispatchers.IO) { - - var sink: BufferedSink? = null - var source: Source? = null - var outputStream: OutputStream? = null - - try { - - - outputStream = FileOutputStream(file) - sink = outputStream.sink().buffer() - source = ByteArrayInputStream(byteArray).source() - sink.writeAll(source) - sink.flush() - - } catch (e: IOException) { - Log.w("Fluwx", "failed to create cache files") - } finally { - sink?.close() - source?.close() - outputStream?.close() - } - - file - } -} - -@Throws(IOException::class) -internal fun copyFile(sourceFilePath: String, destinationDirPath: String):File { - val sourceFile = File(sourceFilePath) - val destinationDir = File(destinationDirPath) - - if (!destinationDir.exists()) { - destinationDir.mkdirs() - } - - val destinationFile = File(destinationDir, sourceFile.name) - return sourceFile.copyTo(destinationFile, overwrite = true) -} diff --git a/android/src/main/kotlin/com/jarvan/fluwx/io/ImagesIO.kt b/android/src/main/kotlin/com/jarvan/fluwx/io/ImagesIO.kt deleted file mode 100644 index 1405379f..00000000 --- a/android/src/main/kotlin/com/jarvan/fluwx/io/ImagesIO.kt +++ /dev/null @@ -1,131 +0,0 @@ -package com.jarvan.fluwx.io - -import android.content.Context -import android.graphics.Bitmap -import android.graphics.Bitmap.CompressFormat -import android.graphics.BitmapFactory -import id.zelory.compressor.Compressor -import id.zelory.compressor.constraint.size -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import okio.* -import java.io.* -import java.io.IOException -import java.util.* -import kotlin.math.sqrt - -/*** - * Created by mo on 2020/3/7 - * 冷风如刀,以大地为砧板,视众生为鱼肉。 - * 万里飞雪,将穹苍作烘炉,熔万物为白银。 - **/ -class ImagesIOIml(override val image: WeChatFile) : ImagesIO { - - override suspend fun readByteArray(): ByteArray = image.readByteArray() - - override suspend fun compressedByteArray(context: Context, maxSize: Int): ByteArray = - withContext(Dispatchers.IO) { - val originalByteArray = readByteArray() - if (originalByteArray.isEmpty()) - return@withContext originalByteArray - - val originFile = inputStreamToFile(ByteArrayInputStream(originalByteArray)) - if (image.suffix.contains("gif")) { - return@withContext originalByteArray - } - val compressedFile = Compressor.compress(context, originFile) { - size(maxFileSize = maxSize * 1024L) - } - - if (compressedFile.length() < maxSize) { - val source = compressedFile.source() - val bufferedSource = source.buffer() - val bytes = bufferedSource.readByteArray() - source.close() - bufferedSource.close() - bytes - } else { - createScaledBitmapWithRatio(compressedFile, maxSize) - } - } - - private fun inputStreamToFile(inputStream: InputStream): File { - val file = File.createTempFile(UUID.randomUUID().toString(), image.suffix) - - val outputStream: OutputStream = FileOutputStream(file) - val sink = outputStream.sink().buffer() - val source = inputStream.source() - sink.writeAll(source) - source.close() - sink.close() - - return file - } - - private fun createScaledBitmapWithRatio(file: File, maxSize: Int): ByteArray { - val originBitmap = BitmapFactory.decodeFile(file.absolutePath) - val result: Bitmap? = createScaledBitmapWithRatio(originBitmap, maxSize, true) - result ?: return byteArrayOf() - - return bmpToByteArray(result, image.suffix) ?: byteArrayOf() - } - - private fun createScaledBitmapWithRatio( - bitmap: Bitmap, - maxLength: Int, - recycle: Boolean - ): Bitmap? { - var result = bitmap - while (true) { - val ratio = maxLength.toDouble() / result.byteCount - val width = result.width * sqrt(ratio) - val height = result.height * sqrt(ratio) - val tmp = Bitmap.createScaledBitmap(result, width.toInt(), height.toInt(), true) - if (result != bitmap) { - result.recycle() - } - result = tmp - if (result.byteCount <= maxLength) { - break - } - } - if (recycle) { - bitmap.recycle() - } - return result - } - - private fun bmpToByteArray( - bitmap: Bitmap, - suffix: String - ): ByteArray? { // int bytes = bitmap.getByteCount(); - - val byteArrayOutputStream = ByteArrayOutputStream() - var format = CompressFormat.PNG - if (suffix.lowercase(Locale.US) == ".jpg" || suffix.lowercase(Locale.US) == ".jpeg") { - format = CompressFormat.JPEG - } - bitmap.compress(format, 100, byteArrayOutputStream) - val inputStream: InputStream = ByteArrayInputStream(byteArrayOutputStream.toByteArray()) - var result: ByteArray? = null - - bitmap.recycle() - - val source = inputStream.source() - val bufferedSource = source.buffer() - try { - result = bufferedSource.readByteArray() - source.close() - bufferedSource.close() - } catch (e: IOException) { - e.printStackTrace() - } - return result - } -} - -interface ImagesIO { - val image: WeChatFile - suspend fun readByteArray(): ByteArray - suspend fun compressedByteArray(context: Context, maxSize: Int): ByteArray -} diff --git a/android/src/main/kotlin/com/jarvan/fluwx/io/WeChatFiles.kt b/android/src/main/kotlin/com/jarvan/fluwx/io/WeChatFiles.kt deleted file mode 100644 index 1aa76505..00000000 --- a/android/src/main/kotlin/com/jarvan/fluwx/io/WeChatFiles.kt +++ /dev/null @@ -1,141 +0,0 @@ -package com.jarvan.fluwx.io - -import android.content.res.AssetFileDescriptor -import android.util.Log -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import okhttp3.OkHttpClient -import okhttp3.Request -import okio.BufferedSource -import okio.buffer -import okio.source -import java.io.File -import java.io.FileNotFoundException -import java.io.IOException - -/*** - * Created by mo on 2020/5/13 - * 冷风如刀,以大地为砧板,视众生为鱼肉。 - * 万里飞雪,将穹苍作烘炉,熔万物为白银。 - **/ - - -class WeChatFileFile(override val source: Any, override val suffix: String) : WeChatFile { - private var internalSource: File - - init { - if (source !is File) - throw IllegalArgumentException("source should be File but it's ${source::class.java.name}") - else - internalSource = source - } - - override suspend fun readByteArray(): ByteArray = withContext(Dispatchers.IO) { - var source: BufferedSource? = null - try { - source = internalSource.source().buffer() - val array = source.readByteArray() - array - } catch (e: FileNotFoundException) { - byteArrayOf() - } catch (io: IOException) { - byteArrayOf() - } finally { - source?.close() - } - } -} - -private class WeChatAssetFile(override val source: Any, override val suffix: String) : WeChatFile { - private var internalSource: AssetFileDescriptor - - init { - if (source !is AssetFileDescriptor) - throw IllegalArgumentException("source should be AssetFileDescriptor but it's ${source::class.java.name}") - else - internalSource = source - } - - override suspend fun readByteArray(): ByteArray = withContext(Dispatchers.IO) { - var source: BufferedSource? = null - try { - source = internalSource.createInputStream().source().buffer() - val array = source.readByteArray() - array - } catch (e: FileNotFoundException) { - byteArrayOf() - } catch (io: IOException) { - byteArrayOf() - } finally { - source?.close() - } - } -} - -private class WeChatNetworkFile(override val source: Any, override val suffix: String) : WeChatFile { - private var internalSource: String - - init { - if (source !is String) - throw IllegalArgumentException("source should be String but it's ${source::class.java.name}") - else - internalSource = source - } - - override suspend fun readByteArray(): ByteArray = withContext(Dispatchers.IO) { - val okHttpClient = OkHttpClient.Builder().build() - val request: Request = Request.Builder().url(internalSource).get().build() - try { - val response = okHttpClient.newCall(request).execute() - val responseBody = response.body - if (response.isSuccessful && responseBody != null) { - responseBody.bytes() - } else { - byteArrayOf() - } - } catch (e: IOException) { - Log.w("Fluwx", "reading file from $internalSource failed") - byteArrayOf() - } - } -} - -private class WeChatMemoryFile(override val source: Any, override val suffix: String) : WeChatFile { - private var internalSource: ByteArray - - init { - if (source !is ByteArray) - throw IllegalArgumentException("source should be String but it's ${source::class.java.name}") - else - internalSource = source - } - - override suspend fun readByteArray(): ByteArray = internalSource -} - -interface WeChatFile { - val source: Any - val suffix: String - - suspend fun readByteArray(): ByteArray - - companion object { - // NETWORK, -// ASSET, -// FILE, -// BINARY, - fun createWeChatFile(params: Map, assetFileDescriptor: (String) -> AssetFileDescriptor): WeChatFile { -// Map toMap() => {"source": source, "schema": schema.index, "suffix": suffix}; - val suffix = (params["suffix"] as String?) ?: ".jpeg" - return when ((params["schema"] as? Int) ?: 0) { - 0 -> WeChatNetworkFile(source = (params["source"] as? String).orEmpty(), suffix = suffix) - 1 -> WeChatAssetFile(source = assetFileDescriptor(((params["source"] as? String).orEmpty())), suffix = suffix) - 2 -> WeChatFileFile(source = File((params["source"] as? String).orEmpty()), suffix = suffix) - 3 -> WeChatMemoryFile(source = (params["source"] as? ByteArray) - ?: byteArrayOf(), suffix = suffix) - else -> WeChatNetworkFile(source = (params["source"] as? String).orEmpty(), suffix = suffix) - } - } - } -} - diff --git a/android/src/main/kotlin/com/jarvan/fluwx/utils/FluwxExtensions.kt b/android/src/main/kotlin/com/jarvan/fluwx/utils/FluwxExtensions.kt deleted file mode 100644 index 51fb1a84..00000000 --- a/android/src/main/kotlin/com/jarvan/fluwx/utils/FluwxExtensions.kt +++ /dev/null @@ -1,54 +0,0 @@ -package com.jarvan.fluwx.utils - -import android.app.Activity -import android.content.ActivityNotFoundException -import android.content.Context -import android.content.Intent -import android.content.pm.PackageManager -import android.os.Bundle -import android.util.Log -import com.jarvan.fluwx.FluwxConfigurations - -internal const val KEY_FLUWX_REQUEST_INFO_EXT_MSG = "KEY_FLUWX_REQUEST_INFO_EXT_MSG" -internal const val KEY_FLUWX_REQUEST_INFO_BUNDLE = "KEY_FLUWX_REQUEST_INFO_BUNDLE" -internal const val KEY_FLUWX_EXTRA = "KEY_FLUWX_EXTRA" -internal const val FLAG_PAYLOAD_FROM_WECHAT = "FLAG_PAYLOAD_FROM_WECHAT" - -internal fun Activity.startFlutterActivity( - extra: Intent, -) { - flutterActivityIntent()?.also { intent -> - intent.addFluwxExtras() - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) - intent.putExtra(KEY_FLUWX_EXTRA, extra) - intent.putExtra(FLAG_PAYLOAD_FROM_WECHAT, true) - try { - startActivity(intent) - } catch (e: ActivityNotFoundException) { - Log.w("fluwx", "Can not start activity for Intent: $intent") - } - } -} - - -internal fun Context.flutterActivityIntent(): Intent? { - return if (FluwxConfigurations.flutterActivity.isBlank()) { - packageManager.getLaunchIntentForPackage(packageName) - } else { - Intent().also { - it.setClassName(this, "${packageName}.${FluwxConfigurations.flutterActivity}") - } - } -} - -internal fun Intent.addFluwxExtras() { - putExtra("fluwx_payload_from_fluwx", true) -} - -internal fun Intent.readWeChatCallbackIntent(): Intent? { - return if (getBooleanExtra(FLAG_PAYLOAD_FROM_WECHAT, false)) { - getParcelableExtra(KEY_FLUWX_EXTRA) - } else { - null - } -} diff --git a/android/src/main/kotlin/com/jarvan/fluwx/utils/WXApiUtils.java b/android/src/main/kotlin/com/jarvan/fluwx/utils/WXApiUtils.java deleted file mode 100644 index 915bab90..00000000 --- a/android/src/main/kotlin/com/jarvan/fluwx/utils/WXApiUtils.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.jarvan.fluwx.utils; - -import java.io.UnsupportedEncodingException; -import java.security.MessageDigest; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; -import java.util.SortedMap; -import java.util.TreeMap; - -public class WXApiUtils { - - public static String createSign(String appId, String nonceStr, String timestamp, String card_type) { - SortedMap parameters = new TreeMap<>(); - parameters.put("app_id", appId); - parameters.put("nonce_str", nonceStr); - parameters.put("card_type", timestamp); - parameters.put("time_stamp", card_type); - StringBuffer sb = new StringBuffer(); - Set es = parameters.entrySet(); - // 所有参与传参的参数按照accsii排序(升序) - Iterator it = es.iterator(); - while (it.hasNext()) { - @SuppressWarnings("rawtypes") - Map.Entry entry = (Map.Entry) it.next(); - String k = (String) entry.getKey(); - Object v = entry.getValue(); - if (null != v && !"".equals(v) && !"sign".equals(k) - && !"key".equals(k)) { - sb.append(k + "=" + v + "&"); - } - } - String sign = shaEncode(sb.toString()).toUpperCase(); - return sign; - } - - - public static String shaEncode(String inStr) { - MessageDigest sha = null; - try { - sha = MessageDigest.getInstance("SHA"); - } catch (Exception e) { - System.out.println(e.toString()); - e.printStackTrace(); - return ""; - } - - byte[] byteArray = new byte[0]; - try { - byteArray = inStr.getBytes("UTF-8"); - } catch (UnsupportedEncodingException e) { - e.printStackTrace(); - } - byte[] md5Bytes = sha.digest(byteArray); - StringBuffer hexValue = new StringBuffer(); - for (int i = 0; i < md5Bytes.length; i++) { - int val = ((int) md5Bytes[i]) & 0xff; - if (val < 16) { - hexValue.append("0"); - } - hexValue.append(Integer.toHexString(val)); - } - return hexValue.toString(); - } - -} diff --git a/android/src/main/kotlin/com/jarvan/fluwx/wxapi/FluwxWXEntryActivity.kt b/android/src/main/kotlin/com/jarvan/fluwx/wxapi/FluwxWXEntryActivity.kt deleted file mode 100644 index d1ef0071..00000000 --- a/android/src/main/kotlin/com/jarvan/fluwx/wxapi/FluwxWXEntryActivity.kt +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2020 The OpenFlutter Organization - * - * 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. - */ -package com.jarvan.fluwx.wxapi - -import android.app.Activity -import android.content.Intent -import android.os.Bundle -import com.jarvan.fluwx.utils.startFlutterActivity - - -open class FluwxWXEntryActivity : Activity() { - - // IWXAPI 是第三方app和微信通信的openapi接口 - - public override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - startFlutterActivity(intent) - finish() - } - - override fun onNewIntent(intent: Intent) { - super.onNewIntent(intent) - startFlutterActivity(intent) - finish() - } - -} \ No newline at end of file diff --git a/android/src/main/res/values/styles.xml b/android/src/main/res/values/styles.xml deleted file mode 100644 index c64332ba..00000000 --- a/android/src/main/res/values/styles.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - \ No newline at end of file diff --git a/android/src/main/res/xml/fluwx_file_provider_paths.xml b/android/src/main/res/xml/fluwx_file_provider_paths.xml deleted file mode 100644 index 70e60b4f..00000000 --- a/android/src/main/res/xml/fluwx_file_provider_paths.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/android/src/test/kotlin/com/jarvan/fluwx/FluwxPluginTest.kt b/android/src/test/kotlin/com/jarvan/fluwx/FluwxPluginTest.kt deleted file mode 100644 index 0f5faf68..00000000 --- a/android/src/test/kotlin/com/jarvan/fluwx/FluwxPluginTest.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.jarvan.fluwx - - -/* - * This demonstrates a simple unit test of the Kotlin portion of this plugin's implementation. - * - * Once you have built the plugin's example app, you can run these tests from the command - * line by running `./gradlew testDebugUnitTest` in the `example/android/` directory, or - * you can run them directly from IDEs that support JUnit such as Android Studio. - */ - -internal class FluwxPluginTest { - -} diff --git a/ios/.gitignore b/ios/.gitignore deleted file mode 100644 index 0c885071..00000000 --- a/ios/.gitignore +++ /dev/null @@ -1,38 +0,0 @@ -.idea/ -.vagrant/ -.sconsign.dblite -.svn/ - -.DS_Store -*.swp -profile - -DerivedData/ -build/ -GeneratedPluginRegistrant.h -GeneratedPluginRegistrant.m - -.generated/ - -*.pbxuser -*.mode1v3 -*.mode2v3 -*.perspectivev3 - -!default.pbxuser -!default.mode1v3 -!default.mode2v3 -!default.perspectivev3 - -xcuserdata - -*.moved-aside - -*.pyc -*sync/ -Icon? -.tags* - -/Flutter/Generated.xcconfig -/Flutter/ephemeral/ -/Flutter/flutter_export_environment.sh \ No newline at end of file diff --git a/ios/Assets/.gitkeep b/ios/Assets/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/ios/Classes/FluwxDelegate.m b/ios/Classes/FluwxDelegate.m deleted file mode 100644 index 3c57171f..00000000 --- a/ios/Classes/FluwxDelegate.m +++ /dev/null @@ -1,27 +0,0 @@ -// -// FluwxDelegate.m -// fluwx -// -// Created by Mo on 2022/3/6. -// - -#import -#import -#import - -@implementation FluwxDelegate - -+ (instancetype)defaultManager { - static dispatch_once_t onceToken; - static FluwxDelegate *instance; - dispatch_once(&onceToken, ^{ - instance = [[FluwxDelegate alloc] init]; - }); - return instance; -} - -- (void)registerWxAPI:(NSString *)appId universalLink:(NSString *)universalLink { - [WXApi registerApp:appId universalLink:universalLink]; -} - -@end diff --git a/ios/Classes/FluwxPlugin.m b/ios/Classes/FluwxPlugin.m deleted file mode 100644 index e8cd9d18..00000000 --- a/ios/Classes/FluwxPlugin.m +++ /dev/null @@ -1,1596 +0,0 @@ -#import -#import -#import -#import -#import -#import -#import -#import -#import - -NSString *const fluwxKeyTitle = @"title"; -NSString *const fluwxKeyImage = @ "image"; -NSString *const fluwxKeyImageData = @ "imageData"; -NSString *const fluwxKeyDescription = @"description"; -NSString *const fluwxKeyMsgSignature = @"msgSignature"; -NSString *const fluwxKeyThumbData = @"thumbData"; -NSString *const fluwxKeyThumbDataHash = @"thumbDataHash"; - -NSString *const fluwxKeyPackage = @"?package="; - -NSString *const fluwxKeyMessageExt = @"messageExt"; -NSString *const fluwxKeyMediaTagName = @"mediaTagName"; -NSString *const fluwxKeyMessageAction = @"messageAction"; - -NSString *const fluwxKeyScene = @"scene"; -NSString *const fluwxKeyTimeline = @"timeline"; -NSString *const fluwxKeySession = @"session"; -NSString *const fluwxKeyFavorite = @"favorite"; - -NSString *const keySource = @"source"; -NSString *const keySuffix = @"suffix"; - -CGFloat thumbnailWidth; - -NSUInteger defaultThumbnailSize = 32 * 1024; - -@interface FluwxPlugin() - -@property (strong, nonatomic)NSString *extMsg; - -@end - -typedef void(^FluwxWXReqRunnable)(void); - -@implementation FluwxPlugin { - FlutterMethodChannel *_channel; - WechatAuthSDK *_qrauth; - BOOL _isRunning; - BOOL _attemptToResumeMsgFromWxFlag; - FluwxWXReqRunnable _attemptToResumeMsgFromWxRunnable; - // cache open url request when WXApi is not registered, and handle it once WXApi is registered - FluwxWXReqRunnable _cachedOpenUrlRequest; -} - -const NSString *errStr = @"errStr"; -const NSString *errCode = @"errCode"; -const NSString *openId = @"openId"; -const NSString *fluwxType = @"type"; -const NSString *lang = @"lang"; -const NSString *country = @"country"; -const NSString *description = @"description"; - -BOOL handleOpenURLByFluwx = YES; - -NSObject *_fluwxRegistrar; - -+ (void)registerWithRegistrar:(NSObject *)registrar { - _fluwxRegistrar = registrar; - FlutterMethodChannel *channel = - [FlutterMethodChannel methodChannelWithName:@"com.jarvanmo/fluwx" - binaryMessenger:[registrar messenger]]; - FluwxPlugin *instance = [[FluwxPlugin alloc] initWithChannel:channel]; - [registrar addApplicationDelegate:instance]; - [registrar addSceneDelegate:instance]; - [registrar addMethodCallDelegate:instance channel:channel]; -} - -- (instancetype)initWithChannel:(FlutterMethodChannel *)channel { - self = [super init]; - if (self) { - _channel = channel; - _qrauth = [[WechatAuthSDK alloc] init]; - _qrauth.delegate = self; - _isRunning = NO; - thumbnailWidth = 150; - _attemptToResumeMsgFromWxFlag = NO; -#if WECHAT_LOGGING - [WXApi startLogByLevel:WXLogLevelDetail logBlock:^(NSString *log) { - [self logToFlutterWithDetail:log]; - }]; -#endif - } - return self; -} - -- (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result { - if ([@"registerApp" isEqualToString:call.method]) { - [self registerApp:call result:result]; - } else if ([@"isWeChatInstalled" isEqualToString:call.method]) { - [self checkWeChatInstallation:call result:result]; - } else if ([@"sendAuth" isEqualToString:call.method]) { - [self handleAuth:call result:result]; - } else if ([@"authByQRCode" isEqualToString:call.method]) { - [self authByQRCode:call result:result]; - } else if ([@"stopAuthByQRCode" isEqualToString:call.method]) { - [self stopAuthByQRCode:call result:result]; - } else if ([@"openWXApp" isEqualToString:call.method]) { - result(@([WXApi openWXApp])); - } else if ([@"launchMiniProgram" isEqualToString:call.method]) { - [self handleLaunchMiniProgram:call result:result]; - } else if ([@"subscribeMsg" isEqualToString:call.method]) { - [self handleSubscribeWithCall:call result:result]; - } else if ([@"autoDeduct" isEqualToString:call.method]) { - [self handleAutoDeductWithCall:call result:result]; - } else if ([@"autoDeductV2" isEqualToString:call.method]) { - [self handleautoDeductV2:call result:result]; - } else if ([@"openBusinessView" isEqualToString:call.method]) { - [self handleOpenBusinessView:call result:result]; - } else if ([@"authByPhoneLogin" isEqualToString:call.method]) { - [self handleAuthByPhoneLogin:call result:result]; - } else if ([@"getExtMsg" isEqualToString:call.method]) { - [self handelGetExtMsgWithCall:call result:result]; - } else if ([call.method hasPrefix:@"share"]) { - [self handleShare:call result:result]; - } else if ([@"openWeChatCustomerServiceChat" isEqualToString:call.method]) { - [self openWeChatCustomerServiceChat:call result:result]; - } else if ([@"checkSupportOpenBusinessView" isEqualToString:call.method]) { - [self checkSupportOpenBusinessView:call result:result]; - } else if ([@"openRankList" isEqualToString:call.method]) { - [self handleOpenRankListCall:call result:result]; - } else if ([@"openUrl" isEqualToString:call.method]) { - [self handleOpenUrlCall:call result:result]; - } else if ([@"openWeChatInvoice" isEqualToString:call.method]) { - [self openWeChatInvoice:call result:result]; - } else if ([@"selfCheck" isEqualToString:call.method]) { -#ifndef __OPTIMIZE__ - [WXApi checkUniversalLinkReady:^(WXULCheckStep step, WXCheckULStepResult *result) { - NSString *log = [NSString stringWithFormat:@"%@, %u, %@, %@", @(step), result.success, result.errorInfo, result.suggestion]; - [self logToFlutterWithDetail:log]; - }]; -#endif - result(nil); - } else if ([@"attemptToResumeMsgFromWx" isEqualToString:call.method]) { - if (_attemptToResumeMsgFromWxRunnable != nil) { - _attemptToResumeMsgFromWxRunnable(); - _attemptToResumeMsgFromWxRunnable = nil; - } - result(nil); - } else if ([@"payWithFluwx" isEqualToString:call.method]) { -#ifndef NO_PAY - [self handlePayment:call result:result]; -#else - result(@NO); -#endif - } else if ([@"payWithHongKongWallet" isEqualToString:call.method]) { -#ifndef NO_PAY - [self handleHongKongWalletPayment:call result:result]; -#else - result(@NO); -#endif - } else { - result(FlutterMethodNotImplemented); - } -} - -- (void)openWeChatInvoice:(FlutterMethodCall *)call result:(FlutterResult)result { - - NSString *appId = call.arguments[@"appId"]; - - if ([FluwxStringUtil isBlank:appId]) { - result([FlutterError - errorWithCode:@"invalid app id" - message:@"are you sure your app id is correct ? " - details:appId]); - return; - } - - WXChooseInvoiceReq *chooseInvoiceReq = [[WXChooseInvoiceReq alloc] init]; - chooseInvoiceReq.appID = appId; - chooseInvoiceReq.timeStamp = [[NSDate date] timeIntervalSince1970]; - chooseInvoiceReq.signType = @"SHA1"; - chooseInvoiceReq.cardSign = @""; - chooseInvoiceReq.nonceStr = @""; - [WXApi sendReq:chooseInvoiceReq completion:^(BOOL done) { - result(@(done)); - }]; -} - -- (void)registerApp:(FlutterMethodCall *)call result:(FlutterResult)result { - NSNumber *doOnIOS = call.arguments[@"iOS"]; - - if (![doOnIOS boolValue]) { - result(@NO); - return; - } - - NSString *appId = call.arguments[@"appId"]; - if ([FluwxStringUtil isBlank:appId]) { - result([FlutterError - errorWithCode:@"invalid app id" - message:@"are you sure your app id is correct ? " - details:appId]); - return; - } - - NSString *universalLink = call.arguments[@"universalLink"]; - - if ([FluwxStringUtil isBlank:universalLink]) { - result([FlutterError - errorWithCode:@"invalid universal link" - message:@"are you sure your universal link is correct ? " - details:universalLink]); - return; - } - - BOOL isWeChatRegistered = [WXApi registerApp:appId universalLink:universalLink]; - - // If registration fails, we can return immediately - if (!isWeChatRegistered) { - result(@(isWeChatRegistered)); - _isRunning = NO; - return; - } - - // Otherwise, since WXApi is now registered successfully, - // we can (and should) immediately handle the previously cached `app:openURL` event (if any) - if (_cachedOpenUrlRequest != nil) { - _cachedOpenUrlRequest(); - _cachedOpenUrlRequest = nil; - } - - // Set `_isRunning` after calling `_cachedOpenUrlRequest` to ensure that - // the `onReq` triggered by this call to `_cachedOpenUrlRequest` will - // be stored in `_attemptToResumeMsgFromWxRunnable` which can be obtained - // by triggering `attemptToResumeMsgFromWx`. - // - // At the same time, this also coincides with the approach on the Android side: - // cold start events are cached and triggered through `attemptToResumeMsgFromWx` - _isRunning = isWeChatRegistered; - - result(@(isWeChatRegistered)); -} - -- (void)checkWeChatInstallation:(FlutterMethodCall *)call result:(FlutterResult)result { - result(@([WXApi isWXAppInstalled])); -} - -- (void)openWeChatCustomerServiceChat:(FlutterMethodCall *)call result:(FlutterResult)result { - NSString *url = call.arguments[@"url"]; - NSString *corpId = call.arguments[@"corpId"]; - - WXOpenCustomerServiceReq *req = [[WXOpenCustomerServiceReq alloc] init]; - req.corpid = corpId; //企业ID - req.url = url; //客服URL - return [WXApi sendReq:req completion:^(BOOL success) { - result(@(success)); - }]; -} - -- (void)checkSupportOpenBusinessView:(FlutterMethodCall *)call result:(FlutterResult)result { - if (![WXApi isWXAppInstalled]) { - result([FlutterError errorWithCode:@"WeChat Not Installed" message:@"Please install the WeChat first" details:nil]); - } else { - result(@(YES)); - } -} - -#ifndef NO_PAY -- (void)handlePayment:(FlutterMethodCall *)call result:(FlutterResult)result { - NSNumber *timestamp = call.arguments[@"timeStamp"]; - - NSString *partnerId = call.arguments[@"partnerId"]; - NSString *prepayId = call.arguments[@"prepayId"]; - NSString *packageValue = call.arguments[@"packageValue"]; - NSString *nonceStr = call.arguments[@"nonceStr"]; - UInt32 timeStamp = [timestamp unsignedIntValue]; - NSString *sign = call.arguments[@"sign"]; - [FluwxDelegate defaultManager].extData = call.arguments[@"extData"]; - - NSString *appId = call.arguments[@"appId"]; - PayReq *req = [[PayReq alloc] init]; - req.openID = (appId == (id) [NSNull null]) ? nil : appId; - req.partnerId = partnerId; - req.prepayId = prepayId; - req.nonceStr = nonceStr; - req.timeStamp = timeStamp; - req.package = packageValue; - req.sign = sign; - - [WXApi sendReq:req completion:^(BOOL done) { - result(@(done)); - }]; - -} - -- (void)handleHongKongWalletPayment:(FlutterMethodCall *)call result:(FlutterResult)result { - NSString *partnerId = call.arguments[@"prepayId"]; - - WXOpenBusinessWebViewReq *req = [[WXOpenBusinessWebViewReq alloc] init]; - req.businessType = 1; - NSMutableDictionary *queryInfoDic = [NSMutableDictionary dictionary]; - [queryInfoDic setObject:partnerId forKey:@"token"]; - req.queryInfoDic = queryInfoDic; - [WXApi sendReq:req completion:^(BOOL done) { - result(@(done)); - }]; -} -#endif - -- (void)handleLaunchMiniProgram:(FlutterMethodCall *)call result:(FlutterResult)result { - NSString *userName = call.arguments[@"userName"]; - NSString *path = call.arguments[@"path"]; - //WXMiniProgramType *miniProgramType = call.arguments[@"miniProgramType"]; - - NSNumber *typeInt = call.arguments[@"miniProgramType"]; - WXMiniProgramType miniProgramType = WXMiniProgramTypeRelease; - if ([typeInt isEqualToNumber:@1]) { - miniProgramType = WXMiniProgramTypeTest; - } else if ([typeInt isEqualToNumber:@2]) { - miniProgramType = WXMiniProgramTypePreview; - } - - WXLaunchMiniProgramReq *launchMiniProgramReq = [WXLaunchMiniProgramReq object]; - launchMiniProgramReq.userName = userName; - launchMiniProgramReq.path = (path == (id) [NSNull null]) ? nil : path; - launchMiniProgramReq.miniProgramType = miniProgramType; - - [WXApi sendReq:launchMiniProgramReq completion:^(BOOL done) { - result(@(done)); - }]; -} - - -- (void)handleSubscribeWithCall:(FlutterMethodCall *)call result:(FlutterResult)result { - NSDictionary *params = call.arguments; - NSString *appId = [params valueForKey:@"appId"]; - NSNumber *scene = [params valueForKey:@"scene"]; - NSString *templateId = [params valueForKey:@"templateId"]; - NSString *reserved = [params valueForKey:@"reserved"]; - - WXSubscribeMsgReq *req = [WXSubscribeMsgReq new]; -#if __LP64__ - req.scene = [scene unsignedIntValue]; -#else - req.scene = [scene unsignedLongValue]; -#endif - req.templateId = templateId; - req.reserved = reserved; - req.openID = appId; - - [WXApi sendReq:req completion:^(BOOL done) { - result(@(done)); - }]; -} - -- (void)handleAutoDeductWithCall:(FlutterMethodCall *)call result:(FlutterResult)result { - NSMutableDictionary *paramsFromDart = [NSMutableDictionary dictionaryWithDictionary:call.arguments]; - [paramsFromDart removeObjectForKey:@"businessType"]; - WXOpenBusinessWebViewReq *req = [[WXOpenBusinessWebViewReq alloc] init]; - NSNumber *businessType = call.arguments[@"businessType"]; - req.businessType = [businessType unsignedIntValue]; - req.queryInfoDic = paramsFromDart; - [WXApi sendReq:req completion:^(BOOL done) { - result(@(done)); - }]; -} - -- (void)handleautoDeductV2:(FlutterMethodCall *)call result:(FlutterResult)result { - NSMutableDictionary *paramsFromDart = call.arguments[@"queryInfo"]; - // [paramsFromDart removeObjectForKey:@"businessType"]; - WXOpenBusinessWebViewReq *req = [[WXOpenBusinessWebViewReq alloc] init]; - NSNumber *businessType = call.arguments[@"businessType"]; - req.businessType = [businessType unsignedIntValue]; - req.queryInfoDic = paramsFromDart; - [WXApi sendReq:req completion:^(BOOL done) { - result(@(done)); - }]; -} - -- (void)handleOpenBusinessView:(FlutterMethodCall *)call result:(FlutterResult)result { - NSDictionary *params = call.arguments; - - WXOpenBusinessViewReq *req = [WXOpenBusinessViewReq object]; - NSString *businessType = [params valueForKey:@"businessType"]; - NSString *query = [params valueForKey:@"query"]; - req.businessType = businessType; - req.query = query; - req.extInfo = @"{\"miniProgramType\":0}"; - [WXApi sendReq:req completion:^(BOOL done) { - result(@(done)); - }]; -} - -- (void)handelGetExtMsgWithCall:(FlutterMethodCall *)call result:(FlutterResult)result { - result([FluwxDelegate defaultManager].extMsg); - [FluwxDelegate defaultManager].extMsg = nil; -} - - -// Deprecated since iOS 9 -// See https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623073-application?language=objc -// Use `application:openURL:options:` instead. -- (BOOL)application:(UIApplication *)application - openURL:(NSURL *)url - sourceApplication:(NSString *)sourceApplication - annotation:(id)annotation { - // Since flutter has minimum iOS version requirement of 11.0, we don't need to change the implementation here. - return [WXApi handleOpenURL:url delegate:self]; -} - -// Deprecated since iOS 9 -// See https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1622964-application?language=objc -// Use `application:openURL:options:` instead. -//- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url { -// // Since flutter has minimum iOS version requirement of 11.0, we don't need to change the implementation here. -// return [WXApi handleOpenURL:url delegate:self]; -//} - - -// Available on iOS 9.0 and later -// See https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623112-application?language=objc -- (BOOL)application:(UIApplication *)app - openURL:(NSURL *)url - options:(NSDictionary *)options { - // ↓ previous solution -- according to document, this may fail if the WXApi hasn't registered yet. - // return [WXApi handleOpenURL:url delegate:self]; - - if (_isRunning) { - // registered -- directly handle open url request by WXApi - return [WXApi handleOpenURL:url delegate:self]; - } else { - // unregistered -- cache open url request and handle it once WXApi is registered - __weak typeof(self) weakSelf = self; - _cachedOpenUrlRequest = ^() { - __strong typeof(weakSelf) strongSelf = weakSelf; - [WXApi handleOpenURL:url delegate:strongSelf]; - }; - // Let's hold this until the PR contributor send feedback. - //return [url.absoluteString contains:[self fetchWeChatAppId]]; - - // simply return YES to indicate that we can handle open url request later - return NO; - } -} - -- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray *_Nonnull))restorationHandler{ - // TODO: (if need) cache userActivity and handle it once WXApi is registered - return [WXApi handleOpenUniversalLink:userActivity delegate:self]; -} - -- (void)scene:(UIScene *)scene continueUserActivity:(NSUserActivity *)userActivity API_AVAILABLE(ios(13.0)) { - // TODO: (if need) cache userActivity and handle it once WXApi is registered - [WXApi handleOpenUniversalLink:userActivity delegate:self]; -} - -- (void)handleOpenUrlCall:(FlutterMethodCall *)call - result:(FlutterResult)result { - OpenWebviewReq *req = [[OpenWebviewReq alloc] init]; - req.url = call.arguments[@"url"]; - [WXApi sendReq:req - completion:^(BOOL success) { - result(@(success)); - }]; -} - -- (void)handleOpenRankListCall:(FlutterMethodCall *)call - result:(FlutterResult)result { - OpenRankListReq *req = [[OpenRankListReq alloc] init]; - [WXApi sendReq:req - completion:^(BOOL success) { - result(@(success)); - }]; -} - -- (BOOL)handleOpenURL:(NSNotification *)aNotification { - if (handleOpenURLByFluwx) { - NSString *aURLString = [aNotification userInfo][@"url"]; - NSURL *aURL = [NSURL URLWithString:aURLString]; - return [WXApi handleOpenURL:aURL delegate:self]; - } else { - return NO; - } -} - -- (void)logToFlutterWithDetail:(NSString *) detail { - if (_channel != nil) { - NSDictionary *result = @{ - @"detail":detail - }; - [_channel invokeMethod:@"wechatLog" arguments:result]; - } -} - -- (void)handleShare:(FlutterMethodCall *)call result:(FlutterResult)result { - if ([@"shareText" isEqualToString:call.method]) { - [self shareText:call result:result]; - } else if ([@"shareImage" isEqualToString:call.method]) { - [self shareImage:call result:result]; - } else if ([@"shareWebPage" isEqualToString:call.method]) { - [self shareWebPage:call result:result]; - } else if ([@"shareMusic" isEqualToString:call.method]) { - [self shareMusic:call result:result]; - } else if ([@"shareVideo" isEqualToString:call.method]) { - [self shareVideo:call result:result]; - } else if ([@"shareMiniProgram" isEqualToString:call.method]) { - [self shareMiniProgram:call result:result]; - } else if ([@"shareFile" isEqualToString:call.method]) { - [self shareFile:call result:result]; - } else if ([@"shareEmoji" isEqualToString:call.method]) { - [self shareEmoji:call result:result]; - } -} - -- (void)shareText:(FlutterMethodCall *)call result:(FlutterResult)result { - NSString *text = call.arguments[@"source"]; - NSNumber *scene = call.arguments[fluwxKeyScene]; - - [self sendText:text InScene:[self intToWeChatScene:scene] completion:^(BOOL done) { - result(@(done)); - }]; -} - -- (void)shareImage:(FlutterMethodCall *)call result:(FlutterResult)result { - NSNumber *scene = call.arguments[fluwxKeyScene]; - - NSDictionary *sourceImage = call.arguments[keySource]; - - FlutterStandardTypedData *flutterImageData = sourceImage[@"uint8List"]; - NSData *imageData = nil; - if (flutterImageData != nil) { - imageData = flutterImageData.data; - } - - NSString *imageDataHash = sourceImage[@"imgDataHash"]; - - FlutterStandardTypedData *flutterThumbData = call.arguments[fluwxKeyThumbData]; - NSData *thumbData = nil; - if (![flutterThumbData isKindOfClass:[NSNull class]]) { - thumbData = flutterThumbData.data; - } - - dispatch_queue_t globalQueue = dispatch_get_global_queue(0, 0); - dispatch_async(globalQueue, ^{ - dispatch_async(dispatch_get_main_queue(), ^{ - [self sendImageData:imageData - ImgDataHash:imageDataHash - TagName:call.arguments[fluwxKeyMediaTagName] - MessageExt:call.arguments[fluwxKeyMessageExt] - Action:call.arguments[fluwxKeyMessageAction] - InScene:[self intToWeChatScene:scene] - title:call.arguments[fluwxKeyTitle] - description:call.arguments[fluwxKeyDescription] - MsgSignature:call.arguments[fluwxKeyMsgSignature] - ThumbData:thumbData - ThumbDataHash:call.arguments[fluwxKeyThumbDataHash] - completion:^(BOOL done) { - result(@(done)); - }]; - }); - - }); -} - -- (void)shareWebPage:(FlutterMethodCall *)call result:(FlutterResult)result { - NSString *webPageUrl = call.arguments[@"webPage"]; - NSNumber *scene = call.arguments[fluwxKeyScene]; - - FlutterStandardTypedData *flutterThumbData = call.arguments[fluwxKeyThumbData]; - NSData *thumbData = nil; - if (![flutterThumbData isKindOfClass:[NSNull class]]) { - thumbData = flutterThumbData.data; - } - - dispatch_queue_t globalQueue = dispatch_get_global_queue(0, 0); - dispatch_async(globalQueue, ^{ - dispatch_async(dispatch_get_main_queue(), ^{ - [self sendLinkURL:webPageUrl - TagName:call.arguments[fluwxKeyMediaTagName] - Title:call.arguments[fluwxKeyTitle] - Description:call.arguments[fluwxKeyDescription] - MessageExt:call.arguments[fluwxKeyMessageExt] - MessageAction:call.arguments[fluwxKeyMessageAction] - InScene:[self intToWeChatScene:scene] - MsgSignature:call.arguments[fluwxKeyMsgSignature] - ThumbData:thumbData - ThumbDataHash:call.arguments[fluwxKeyThumbDataHash] - completion:^(BOOL done) { - result(@(done)); - }]; - }); - - }); -} - -- (void)shareMusic:(FlutterMethodCall *)call result:(FlutterResult)result { - NSNumber *scene = call.arguments[fluwxKeyScene]; - - FlutterStandardTypedData *flutterThumbData = call.arguments[fluwxKeyThumbData]; - NSData *thumbData = nil; - if (![flutterThumbData isKindOfClass:[NSNull class]]) { - thumbData = flutterThumbData.data; - } - - dispatch_queue_t globalQueue = dispatch_get_global_queue(0, 0); - dispatch_async(globalQueue, ^{ - dispatch_async(dispatch_get_main_queue(), ^{ - [self sendMusicURL:call.arguments[@"musicUrl"] - dataURL:call.arguments[@"musicDataUrl"] - MusicLowBandUrl:call.arguments[@"musicLowBandUrl"] - MusicLowBandDataUrl:call.arguments[@"musicLowBandDataUrl"] - Title:call.arguments[fluwxKeyTitle] - Description:call.arguments[fluwxKeyDescription] - MessageExt:call.arguments[fluwxKeyMessageExt] - MessageAction:call.arguments[fluwxKeyMessageAction] - TagName:call.arguments[fluwxKeyMediaTagName] - InScene:[self intToWeChatScene:scene] - MsgSignature:call.arguments[fluwxKeyMsgSignature] - ThumbData:thumbData - ThumbDataHash:call.arguments[fluwxKeyThumbDataHash] - completion:^(BOOL done) { - result(@(done)); - }]; - }); - }); -} - -- (void)shareVideo:(FlutterMethodCall *)call result:(FlutterResult)result { - NSNumber *scene = call.arguments[fluwxKeyScene]; - - FlutterStandardTypedData *flutterThumbData = call.arguments[fluwxKeyThumbData]; - NSData *thumbData = nil; - if (![flutterThumbData isKindOfClass:[NSNull class]]) { - thumbData = flutterThumbData.data; - } - - dispatch_queue_t globalQueue = dispatch_get_global_queue(0, 0); - dispatch_async(globalQueue, ^{ - dispatch_async(dispatch_get_main_queue(), ^{ - [self sendVideoURL:call.arguments[@"videoUrl"] - VideoLowBandUrl:call.arguments[@"videoLowBandUrl"] - Title:call.arguments[fluwxKeyTitle] - Description:call.arguments[fluwxKeyDescription] - MessageExt:call.arguments[fluwxKeyMessageExt] - MessageAction:call.arguments[fluwxKeyMessageAction] - TagName:call.arguments[fluwxKeyMediaTagName] - InScene:[self intToWeChatScene:scene] - MsgSignature:call.arguments[fluwxKeyMsgSignature] - ThumbData:thumbData - ThumbDataHash:call.arguments[fluwxKeyThumbDataHash] - completion:^(BOOL done) { - result(@(done)); - }]; - }); - }); -} - -- (void)shareFile:(FlutterMethodCall *)call result:(FlutterResult)result { - NSDictionary *sourceFile = call.arguments[keySource]; - NSString *fileExtension; - NSString *suffix = sourceFile[keySuffix]; - fileExtension = suffix; - if ([suffix hasPrefix:@"."]) { - NSRange range = NSMakeRange(0, 1); - fileExtension = [suffix stringByReplacingCharactersInRange:range withString:@""]; - } - - NSData *data = [self getNsDataFromWeChatFile:sourceFile]; - NSNumber *scene = call.arguments[fluwxKeyScene]; - - FlutterStandardTypedData *flutterThumbData = call.arguments[fluwxKeyThumbData]; - NSData *thumbData = nil; - if (![flutterThumbData isKindOfClass:[NSNull class]]) { - thumbData = flutterThumbData.data; - } - - dispatch_queue_t globalQueue = dispatch_get_global_queue(0, 0); - dispatch_async(globalQueue, ^{ - dispatch_async(dispatch_get_main_queue(), ^{ - [self sendFileData:data - fileExtension:fileExtension - Title:call.arguments[fluwxKeyTitle] - Description:call.arguments[fluwxKeyDescription] - InScene:[self intToWeChatScene:scene] - MsgSignature:call.arguments[fluwxKeyMsgSignature] - ThumbData:thumbData - ThumbDataHash:call.arguments[fluwxKeyThumbDataHash] - completion:^(BOOL success) { - result(@(success)); - }]; - }); - }); -} - -- (void)shareMiniProgram:(FlutterMethodCall *)call result:(FlutterResult)result { - NSNumber *scene = call.arguments[fluwxKeyScene]; - - FlutterStandardTypedData *flutterThumbData = call.arguments[fluwxKeyThumbData]; - NSData *thumbData = nil; - if (![flutterThumbData isKindOfClass:[NSNull class]]) { - thumbData = flutterThumbData.data; - } - - FlutterStandardTypedData *hdImageDataPayload = call.arguments[@"hdImageData"]; - NSData *hdImageData = nil; - if (![hdImageDataPayload isKindOfClass:[NSNull class]]) { - hdImageData = hdImageDataPayload.data; - } - - NSNumber *typeInt = call.arguments[@"miniProgramType"]; - WXMiniProgramType miniProgramType = WXMiniProgramTypeRelease; - if ([typeInt isEqualToNumber:@1]) { - miniProgramType = WXMiniProgramTypeTest; - } else if ([typeInt isEqualToNumber:@2]) { - miniProgramType = WXMiniProgramTypePreview; - } - dispatch_queue_t globalQueue = dispatch_get_global_queue(0, 0); - dispatch_async(globalQueue, ^{ - dispatch_async(dispatch_get_main_queue(), ^{ - [self sendMiniProgramWebpageUrl:call.arguments[@"webPageUrl"] - userName:call.arguments[@"userName"] - path:call.arguments[@"path"] - title:call.arguments[fluwxKeyTitle] - Description:call.arguments[fluwxKeyDescription] - withShareTicket:[call.arguments[@"withShareTicket"] boolValue] - miniProgramType:miniProgramType - MessageExt:call.arguments[fluwxKeyMessageExt] - MessageAction:call.arguments[fluwxKeyMessageAction] - TagName:call.arguments[fluwxKeyMediaTagName] - InScene:[self intToWeChatScene:scene] - MsgSignature:call.arguments[fluwxKeyMsgSignature] - HdImageData:hdImageData - ThumbData:thumbData - ThumbDataHash:call.arguments[fluwxKeyThumbDataHash] - completion:^(BOOL done) { - result(@(done)); - }]; - }); - }); -} - -- (void)shareEmoji:(FlutterMethodCall *)call result:(FlutterResult)result { - - NSNumber *sceneNum = call.arguments[fluwxKeyScene]; - enum WXScene scene = [self intToWeChatScene:sceneNum]; - - NSDictionary *sourceEmoji = call.arguments[keySource]; - FlutterStandardTypedData *flutterEmojiData = sourceEmoji[@"uint8List"]; - NSData *emojiData = flutterEmojiData != nil ? flutterEmojiData.data : nil; - - FlutterStandardTypedData *flutterThumbData = call.arguments[fluwxKeyThumbData]; - NSData *thumbData = ![flutterThumbData isKindOfClass:[NSNull class]] ? flutterThumbData.data : nil; - - NSString *msgSignature = call.arguments[fluwxKeyMsgSignature]; - NSString *thumbHash = call.arguments[fluwxKeyThumbDataHash]; - - dispatch_queue_t globalQueue = dispatch_get_global_queue(0, 0); - dispatch_async(globalQueue, ^{ - dispatch_async(dispatch_get_main_queue(), ^{ - - [self sendEmotionData:emojiData - InScene:scene - MsgSignature:msgSignature - ThumbData:thumbData - ThumbDataHash:thumbHash - completion:^(BOOL success) { - result(@(success)); - }]; - }); - }); -} - -- (NSData *)getNsDataFromWeChatFile:(NSDictionary *)weChatFile { - NSNumber *schema = weChatFile[@"schema"]; - - if ([schema isEqualToNumber:@0]) { - NSString *source = weChatFile[keySource]; - NSURL *imageURL = [NSURL URLWithString:source]; - //下载图片 - return [NSData dataWithContentsOfURL:imageURL]; - } else if ([schema isEqualToNumber:@1]) { - NSString *source = weChatFile[keySource]; - return [NSData dataWithContentsOfFile:[self readFileFromAssets:source]]; - } else if ([schema isEqualToNumber:@2]) { - NSString *source = weChatFile[keySource]; - return [NSData dataWithContentsOfFile:source]; - } else if ([schema isEqualToNumber:@3]) { - FlutterStandardTypedData *imageData = weChatFile[@"source"]; - return imageData.data; - } else { - return nil; - } -} - -- (UIImage *)getThumbnailFromNSData:(NSData *)data size:(NSUInteger)size isPNG:(BOOL)isPNG compress:(BOOL)compress { - UIImage *uiImage = [UIImage imageWithData:data]; - if (compress) { - return [ThumbnailHelper compressImage:uiImage toByte:size isPNG:isPNG]; - } else { - return uiImage; - } -} - -- (NSData *)getThumbnailDataFromNSData:(NSData *)data size:(NSUInteger)size compress:(BOOL)compress { - if (compress) { - return [ThumbnailHelper compressImageData:data toByte:size]; - } else { - return data; - } -} - -- (NSString *)readFileFromAssets:(NSString *)imagePath { - NSArray *array = [self formatAssets:imagePath]; - NSString *key; - if ([FluwxStringUtil isBlank:array[1]]) { - key = [_fluwxRegistrar lookupKeyForAsset:array[0]]; - } else { - key = [_fluwxRegistrar lookupKeyForAsset:array[0] fromPackage:array[1]]; - } - - return [[NSBundle mainBundle] pathForResource:key ofType:nil]; -} - -- (NSArray *)formatAssets:(NSString *)originPath { - NSString *path = nil; - NSString *packageName = @""; - NSString *pathWithoutSchema = originPath; - NSInteger indexOfPackage = [pathWithoutSchema lastIndexOfString:@"?package="]; - - if (indexOfPackage != JavaNotFound) { - path = [pathWithoutSchema substringFromIndex:0 toIndex:indexOfPackage]; - NSInteger begin = indexOfPackage + [fluwxKeyPackage length]; - packageName = [pathWithoutSchema substringFromIndex:begin toIndex:[pathWithoutSchema length]]; - } else { - path = pathWithoutSchema; - } - - return @[path, packageName]; -} - -- (BOOL)isPNG:(NSString *)suffix { - return [@".png" equals:suffix]; -} - -- (enum WXScene)intToWeChatScene:(NSNumber *)value { - // enum WeChatScene { SESSION, TIMELINE, FAVORITE } - if ([value isEqual:@0]) { - return WXSceneSession; - } else if ([value isEqual:@1]) { - return WXSceneTimeline; - } else if ([value isEqual:@2]) { - return WXSceneFavorite; - } else { - return WXSceneSession; - } -} - -- (void)managerDidRecvLaunchFromWXReq:(LaunchFromWXReq *)request { - [FluwxDelegate defaultManager].extMsg = request.message.messageExt; - // LaunchFromWXReq *launchFromWXReq = (LaunchFromWXReq *)request; - // - // if (_isRunning) { - // [FluwxDelegate defaultManager].extMsg = request.message.messageExt; - // } else { - // __weak typeof(self) weakSelf = self; - // _initialWXReqRunnable = ^() { - // __strong typeof(weakSelf) strongSelf = weakSelf; - // [FluwxDelegate defaultManager].extMsg = request.message.messageExt - // }; - // } -} - -- (void)onResp:(BaseResp *)resp { - if ([resp isKindOfClass:[SendMessageToWXResp class]]) { - SendMessageToWXResp *messageResp = (SendMessageToWXResp *) resp; - NSDictionary *result = @{ - description: messageResp.description == nil ? @"" : messageResp.description, - errStr: messageResp.errStr == nil ? @"" : messageResp.errStr, - errCode: @(messageResp.errCode), - fluwxType: @(messageResp.type), - country: messageResp.country == nil ? @"" : messageResp.country, - lang: messageResp.lang == nil ? @"" : messageResp.lang}; - if (_channel != nil) { - [_channel invokeMethod:@"onShareResponse" arguments:result]; - } - } else if ([resp isKindOfClass:[SendAuthResp class]]) { - SendAuthResp *authResp = (SendAuthResp *) resp; - NSDictionary *result = @{ - description: authResp.description == nil ? @"" : authResp.description, - errStr: authResp.errStr == nil ? @"" : authResp.errStr, - errCode: @(authResp.errCode), - fluwxType: @(authResp.type), - country: authResp.country == nil ? @"" : authResp.country, - lang: authResp.lang == nil ? @"" : authResp.lang, - @"code": [FluwxStringUtil nilToEmpty:authResp.code], - @"state": [FluwxStringUtil nilToEmpty:authResp.state] - - }; - - if (_channel != nil) { - [_channel invokeMethod:@"onAuthResponse" arguments:result]; - } - } else if ([resp isKindOfClass:[AddCardToWXCardPackageResp class]]) { - // pass - } else if ([resp isKindOfClass:[WXChooseCardResp class]]) { - // pass - } else if ([resp isKindOfClass:[WXChooseInvoiceResp class]]) { - //TODO 处理发票返回,并回调Dart - - WXChooseInvoiceResp *chooseInvoiceResp = (WXChooseInvoiceResp *) resp; - NSArray *array = chooseInvoiceResp.cardAry; - NSMutableArray *mutableArray = [NSMutableArray arrayWithCapacity:array.count]; - for (int i = 0; i< array.count; i++) { - WXInvoiceItem *item = array[i]; - NSDictionary *dict = @{@"app_id":item.appID, @"encrypt_code":item.encryptCode, @"card_id":item.cardId}; - [mutableArray addObject:dict]; - } - - NSError *error = nil; - NSData *jsonData = [NSJSONSerialization dataWithJSONObject:mutableArray - options:NSJSONWritingPrettyPrinted - error: &error]; - NSString *cardItemList = @""; - if ([jsonData length] && error == nil) { - cardItemList = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; - } - - NSDictionary *result = @{ - description: chooseInvoiceResp.description == nil ? @"" : chooseInvoiceResp.description, - errStr: chooseInvoiceResp.errStr == nil ? @"" : chooseInvoiceResp.errStr, - errCode: @(chooseInvoiceResp.errCode), - fluwxType: @(chooseInvoiceResp.type), - @"cardItemList":cardItemList - }; - - if (_channel != nil) { - [_channel invokeMethod:@"onOpenWechatInvoiceResponse" arguments:result]; - } - } else if ([resp isKindOfClass:[WXSubscribeMsgResp class]]) { - WXSubscribeMsgResp *subscribeMsgResp = (WXSubscribeMsgResp *) resp; - NSMutableDictionary *result = [NSMutableDictionary dictionary]; - NSString *openid = subscribeMsgResp.openId; - if (openid != nil && openid != NULL && ![openid isKindOfClass:[NSNull class]]) { - result[@"openid"] = openid; - } - - NSString *templateId = subscribeMsgResp.templateId; - if (templateId != nil && templateId != NULL && ![templateId isKindOfClass:[NSNull class]]) { - result[@"templateId"] = templateId; - } - - NSString *action = subscribeMsgResp.action; - if (action != nil && action != NULL && ![action isKindOfClass:[NSNull class]]) { - result[@"action"] = action; - } - - NSString *reserved = subscribeMsgResp.action; - if (reserved != nil && reserved != NULL && ![reserved isKindOfClass:[NSNull class]]) { - result[@"reserved"] = reserved; - } - - UInt32 scene = subscribeMsgResp.scene; - result[@"scene"] = @(scene); - if (_channel != nil) { - [_channel invokeMethod:@"onSubscribeMsgResp" arguments:result]; - } - } else if ([resp isKindOfClass:[WXLaunchMiniProgramResp class]]) { - WXLaunchMiniProgramResp *miniProgramResp = (WXLaunchMiniProgramResp *) resp; - NSDictionary *commonResult = @{ - description: miniProgramResp.description == nil ? @"" : miniProgramResp.description, - errStr: miniProgramResp.errStr == nil ? @"" : miniProgramResp.errStr, - errCode: @(miniProgramResp.errCode), - fluwxType: @(miniProgramResp.type), - }; - - NSMutableDictionary *result = [NSMutableDictionary dictionaryWithDictionary:commonResult]; - if (miniProgramResp.extMsg != nil) { - result[@"extMsg"] = miniProgramResp.extMsg; - } - if (_channel != nil) { - [_channel invokeMethod:@"onLaunchMiniProgramResponse" arguments:result]; - } - } else if ([resp isKindOfClass:[WXInvoiceAuthInsertResp class]]) { - // pass - } else if ([resp isKindOfClass:[WXOpenBusinessWebViewResp class]]) { - WXOpenBusinessWebViewResp *businessResp = (WXOpenBusinessWebViewResp *) resp; - NSDictionary *result = @{ - description: [FluwxStringUtil nilToEmpty:businessResp.description], - errStr: [FluwxStringUtil nilToEmpty:resp.errStr], - errCode: @(businessResp.errCode), - fluwxType: @(businessResp.type), - @"resultInfo": [FluwxStringUtil nilToEmpty:businessResp.result], - @"businessType": @(businessResp.businessType), - }; - if (_channel != nil) { - [_channel invokeMethod:@"onWXOpenBusinessWebviewResponse" arguments:result]; - } - } else if ([resp isKindOfClass:[WXOpenCustomerServiceResp class]]) { - WXOpenCustomerServiceResp *customerResp = (WXOpenCustomerServiceResp *) resp; - NSDictionary *result = @{ - description: [FluwxStringUtil nilToEmpty:customerResp.description], - errStr: [FluwxStringUtil nilToEmpty:resp.errStr], - errCode: @(customerResp.errCode), - fluwxType: @(customerResp.type), - @"extMsg":[FluwxStringUtil nilToEmpty:customerResp.extMsg] - }; - if (_channel != nil) { - [_channel invokeMethod:@"onWXOpenBusinessWebviewResponse" arguments:result]; - } - // 相关错误信息 - } else if ([resp isKindOfClass:[WXOpenBusinessViewResp class]]) { - WXOpenBusinessViewResp *openBusinessViewResp = (WXOpenBusinessViewResp *) resp; - NSDictionary *result = @{ - description: [FluwxStringUtil nilToEmpty:openBusinessViewResp.description], - errStr: [FluwxStringUtil nilToEmpty:resp.errStr], - errCode: @(openBusinessViewResp.errCode), - @"businessType":openBusinessViewResp.businessType, - fluwxType: @(openBusinessViewResp.type), - @"extMsg":[FluwxStringUtil nilToEmpty:openBusinessViewResp.extMsg] - }; - if (_channel != nil) { - [_channel invokeMethod:@"onOpenBusinessViewResponse" arguments:result]; - } - // 相关错误信息 - } -#ifndef NO_PAY - else if ([resp isKindOfClass:[WXPayInsuranceResp class]]) { - // pass - } else if ([resp isKindOfClass:[PayResp class]]) { - PayResp *payResp = (PayResp *) resp; - NSDictionary *result = @{ - description: [FluwxStringUtil nilToEmpty:payResp.description], - errStr: [FluwxStringUtil nilToEmpty:resp.errStr], - errCode: @(payResp.errCode), - fluwxType: @(payResp.type), - @"extData": [FluwxStringUtil nilToEmpty:[FluwxDelegate defaultManager].extData], - @"returnKey": [FluwxStringUtil nilToEmpty:payResp.returnKey], - }; - [FluwxDelegate defaultManager].extData = nil; - if (_channel != nil) { - [_channel invokeMethod:@"onPayResponse" arguments:result]; - } - } else if ([resp isKindOfClass:[WXNontaxPayResp class]]) { - // pass - } -#endif -} - -- (void)onReq:(BaseReq *)req { - if ([req isKindOfClass:[GetMessageFromWXReq class]]) { - // pass - } else if ([req isKindOfClass:[ShowMessageFromWXReq class]]) { - // ShowMessageFromWXReq -- android spec - ShowMessageFromWXReq *showMessageFromWXReq = (ShowMessageFromWXReq *) req; - WXMediaMessage *wmm = showMessageFromWXReq.message; - - NSMutableDictionary *result = [NSMutableDictionary dictionary]; - [result setValue:wmm.messageAction forKey:@"messageAction"]; - [result setValue:wmm.messageExt forKey:@"extMsg"]; - [result setValue:showMessageFromWXReq.lang forKey:@"lang"]; - [result setValue:showMessageFromWXReq.country forKey:@"country"]; - - // Cache extMsg for later use (by calling 'getExtMsg') - [FluwxDelegate defaultManager].extMsg = wmm.messageExt; - - if (_isRunning) { - [_channel invokeMethod:@"onWXShowMessageFromWX" arguments:result]; - } else { - __weak typeof(self) weakSelf = self; - _attemptToResumeMsgFromWxRunnable = ^() { - __strong typeof(weakSelf) strongSelf = weakSelf; - [strongSelf->_channel invokeMethod:@"onWXShowMessageFromWX" arguments:result]; - }; - } - } else if ([req isKindOfClass:[LaunchFromWXReq class]]) { - // ShowMessageFromWXReq -- ios spec - LaunchFromWXReq *launchFromWXReq = (LaunchFromWXReq *) req; - WXMediaMessage *wmm = launchFromWXReq.message; - - NSMutableDictionary *result = [NSMutableDictionary dictionary]; - [result setValue:wmm.messageAction forKey:@"messageAction"]; - [result setValue:wmm.messageExt forKey:@"extMsg"]; - [result setValue:launchFromWXReq.lang forKey:@"lang"]; - [result setValue:launchFromWXReq.country forKey:@"country"]; - - // Cache extMsg for later use (by calling 'getExtMsg') - [FluwxDelegate defaultManager].extMsg = wmm.messageExt; - - if (_isRunning) { - [_channel invokeMethod:@"onWXLaunchFromWX" arguments:result]; - } else { - __weak typeof(self) weakSelf = self; - _attemptToResumeMsgFromWxRunnable = ^() { - __strong typeof(weakSelf) strongSelf = weakSelf; - [strongSelf->_channel invokeMethod:@"onWXLaunchFromWX" arguments:result]; - }; - } - } -} - -- (void)sendText:(NSString *)text - InScene:(enum WXScene)scene - completion:(void (^ __nullable)(BOOL success))completion { - SendMessageToWXReq *req = [[SendMessageToWXReq alloc] init]; - req.scene = scene; - req.bText = YES; - req.text = text; - [WXApi sendReq:req completion:completion]; -} - -- (void)sendImageData:(NSData *)imageData - ImgDataHash:(NSString *) imgDataHash - TagName:(NSString *)tagName - MessageExt:(NSString *)messageExt - Action:(NSString *)action - InScene:(enum WXScene)scene - title:(NSString *)title - description:(NSString *)description - MsgSignature:(NSString *)msgSignature - ThumbData:(NSData *)thumbData - ThumbDataHash:(NSString*)thumbDataHash - completion:(void (^ __nullable)(BOOL success))completion { - WXImageObject *ext = [WXImageObject object]; - ext.imageData = imageData; - ext.imgDataHash = (imgDataHash == (id) [NSNull null]) ? nil : imgDataHash; - - WXMediaMessage *message = [self messageWithTitle:(title == (id) [NSNull null]) ? nil : title - Description:(description == (id) [NSNull null]) ? nil : description - Object:ext - MessageExt:(messageExt == (id) [NSNull null]) ? nil : messageExt - MessageAction:(action == (id) [NSNull null]) ? nil : action - MediaTag:(tagName == (id) [NSNull null]) ? nil : tagName - MsgSignature:(msgSignature == (id) [NSNull null]) ? nil : msgSignature - ThumbData: thumbData - ThumbDataHash:(thumbDataHash == (id) [NSNull null]) ? nil : thumbDataHash - - ];; - - SendMessageToWXReq *req = [self requestWithText:nil - OrMediaMessage:message - bText:NO - InScene:scene]; - - [WXApi sendReq:req completion:completion]; -} - -- (void)sendLinkURL:(NSString *)urlString - TagName:(NSString *)tagName - Title:(NSString *)title - Description:(NSString *)description - MessageExt:(NSString *)messageExt - MessageAction:(NSString *)messageAction - InScene:(enum WXScene)scene - MsgSignature:(NSString *)msgSignature - ThumbData:(NSData *)thumbData - ThumbDataHash:(NSString*)thumbDataHash - completion:(void (^ __nullable)(BOOL success))completion { - WXWebpageObject *ext = [WXWebpageObject object]; - ext.webpageUrl = urlString; - - WXMediaMessage *message = [self messageWithTitle:(title == (id) [NSNull null]) ? nil :title - Description:(description == (id) [NSNull null]) ? nil : description - Object:ext - MessageExt:(messageExt == (id) [NSNull null]) ? nil : messageExt - MessageAction:(messageAction == (id) [NSNull null]) ? nil : messageAction - MediaTag:(tagName == (id) [NSNull null]) ? nil : tagName - MsgSignature:(msgSignature == (id) [NSNull null]) ? nil : msgSignature - ThumbData: thumbData - ThumbDataHash:(thumbDataHash == (id) [NSNull null]) ? nil : thumbDataHash - ]; - - SendMessageToWXReq *req = [self requestWithText:nil - OrMediaMessage:message - bText:NO - InScene:scene]; - [WXApi sendReq:req completion:completion]; -} - -- (void)sendMusicURL:(NSString *)musicURL - dataURL:(NSString *)dataURL - MusicLowBandUrl:(NSString *)musicLowBandUrl - MusicLowBandDataUrl:(NSString *)musicLowBandDataUrl - Title:(NSString *)title - Description:(NSString *)description - MessageExt:(NSString *)messageExt - MessageAction:(NSString *)messageAction - TagName:(NSString *)tagName - InScene:(enum WXScene)scene - MsgSignature:(NSString *)msgSignature - ThumbData:(NSData *)thumbData - ThumbDataHash:(NSString*)thumbDataHash - completion:(void (^ __nullable)(BOOL success))completion { - WXMusicObject *ext = [WXMusicObject object]; - - if ([FluwxStringUtil isBlank:musicURL]) { - ext.musicLowBandUrl = musicLowBandUrl; - ext.musicLowBandDataUrl = (musicLowBandDataUrl == (id) [NSNull null]) ? nil : musicLowBandDataUrl; - } else { - ext.musicUrl = musicURL; - ext.musicDataUrl = (dataURL == (id) [NSNull null]) ? nil : dataURL; - } - - - WXMediaMessage *message = [self messageWithTitle:(title == (id) [NSNull null]) ? nil : title - Description:description - Object:ext - MessageExt:(messageExt == (id) [NSNull null]) ? nil : messageExt - MessageAction:(messageAction == (id) [NSNull null]) ? nil : messageAction - MediaTag:(tagName == (id) [NSNull null]) ? nil : tagName - MsgSignature:(msgSignature == (id) [NSNull null]) ? nil : msgSignature - ThumbData: thumbData - ThumbDataHash:(thumbDataHash == (id) [NSNull null]) ? nil : thumbDataHash - ]; - - SendMessageToWXReq *req = [self requestWithText:nil - OrMediaMessage:message - bText:NO - InScene:scene]; - - [WXApi sendReq:req completion:completion]; -} - -- (void)sendVideoURL:(NSString *)videoURL - VideoLowBandUrl:(NSString *)videoLowBandUrl - Title:(NSString *)title - Description:(NSString *)description - MessageExt:(NSString *)messageExt - MessageAction:(NSString *)messageAction - TagName:(NSString *)tagName - InScene:(enum WXScene)scene - MsgSignature:(NSString *)msgSignature - ThumbData:(NSData *)thumbData - ThumbDataHash:(NSString*)thumbDataHash - completion:(void (^ __nullable)(BOOL success))completion { - WXMediaMessage *message = [WXMediaMessage message]; - message.title = (title == (id) [NSNull null]) ? nil : title; - message.description = (description == (id) [NSNull null]) ? nil : description; - message.messageExt = (messageExt == (id) [NSNull null]) ? nil : messageExt; - message.messageAction = (messageAction == (id) [NSNull null]) ? nil : messageAction; - message.mediaTagName = (tagName == (id) [NSNull null]) ? nil : tagName; - message.thumbData = (thumbData == (id) [NSNull null]) ? nil : thumbData; - message.thumbDataHash = (thumbDataHash == (id) [NSNull null]) ? nil : thumbDataHash; - - WXVideoObject *ext = [WXVideoObject object]; - if ([FluwxStringUtil isBlank:videoURL]) { - ext.videoLowBandUrl = videoLowBandUrl; - } else { - ext.videoUrl = videoURL; - } - message.mediaObject = ext; - - SendMessageToWXReq *req = [self requestWithText:nil OrMediaMessage:message bText:NO InScene:scene]; - [WXApi sendReq:req completion:completion]; -} - -- (void)sendEmotionData:(NSData *)emotionData - InScene:(enum WXScene)scene - MsgSignature:(NSString *)msgSignature - ThumbData:(NSData *)thumbData - ThumbDataHash:(NSString*)thumbDataHash - completion:(void (^ __nullable)(BOOL success))completion { - WXMediaMessage *message = [WXMediaMessage message]; - message.thumbData = (thumbData == (id) [NSNull null]) ? nil : thumbData; - message.thumbDataHash = (thumbDataHash == (id) [NSNull null]) ? nil : thumbDataHash; - - WXEmoticonObject *ext = [WXEmoticonObject object]; - ext.emoticonData = emotionData; - message.mediaObject = ext; - - NSString *signature = (msgSignature == (id) [NSNull null]) ? nil : msgSignature; - if (signature != nil) { - message.msgSignature = signature; - } - - SendMessageToWXReq *req = [self requestWithText:nil OrMediaMessage:message bText:NO InScene:scene]; - [WXApi sendReq:req completion:completion]; -} - -- (void)sendFileData:(NSData *)fileData - fileExtension:(NSString *)extension - Title:(NSString *)title - Description:(NSString *)description - InScene:(enum WXScene)scene - MsgSignature:(NSString *)msgSignature - ThumbData:(NSData *)thumbData - ThumbDataHash:(NSString*)thumbDataHash - completion:(void (^ __nullable)(BOOL success))completion { - WXMediaMessage *message = [WXMediaMessage message]; - message.title = title; - message.description = description; - message.thumbData = (thumbData == (id) [NSNull null]) ? nil : thumbData; - message.thumbDataHash = (thumbDataHash == (id) [NSNull null]) ? nil : thumbDataHash; - - WXFileObject *ext = [WXFileObject object]; - ext.fileExtension = extension; - ext.fileData = fileData; - message.mediaObject = ext; - - NSString *signature = (msgSignature == (id) [NSNull null]) ? nil : msgSignature; - if (signature != nil) { - message.msgSignature = signature; - } - - SendMessageToWXReq *req = [self requestWithText:nil OrMediaMessage:message bText:NO InScene:scene]; - [WXApi sendReq:req completion:completion]; -} - -- (void)sendMiniProgramWebpageUrl:(NSString *)webpageUrl - userName:(NSString *)userName - path:(NSString *)path - title:(NSString *)title - Description:(NSString *)description - withShareTicket:(BOOL)withShareTicket - miniProgramType:(WXMiniProgramType)programType - MessageExt:(NSString *)messageExt - MessageAction:(NSString *)messageAction - TagName:(NSString *)tagName - InScene:(enum WXScene)scene - MsgSignature:(NSString *)msgSignature - HdImageData:(NSData *)hdImageData - ThumbData:(NSData *)thumbData - ThumbDataHash:(NSString*)thumbDataHash - completion:(void (^ __nullable)(BOOL success))completion { - WXMiniProgramObject *ext = [WXMiniProgramObject object]; - ext.webpageUrl = (webpageUrl == (id) [NSNull null]) ? nil : webpageUrl; - ext.userName = (userName == (id) [NSNull null]) ? nil : userName; - ext.path = (path == (id) [NSNull null]) ? nil : path; - ext.withShareTicket = withShareTicket; - ext.hdImageData = hdImageData; - ext.miniProgramType = programType; - - WXMediaMessage *message = [self messageWithTitle:(title == (id) [NSNull null]) ? nil : title - Description:(description == (id) [NSNull null]) ? nil : description - Object:ext - MessageExt:(messageExt == (id) [NSNull null]) ? nil : messageExt - MessageAction:(messageAction == (id) [NSNull null]) ? nil : messageAction - MediaTag:(tagName == (id) [NSNull null]) ? nil : tagName - MsgSignature:(msgSignature == (id) [NSNull null]) ? nil : msgSignature - ThumbData:(thumbData == (id) [NSNull null] ? nil : thumbData) - ThumbDataHash:(thumbDataHash == (id) [NSNull null]) ? nil : thumbDataHash - ]; - - SendMessageToWXReq *req = [self requestWithText:nil OrMediaMessage:message bText:NO InScene:scene]; - [WXApi sendReq:req completion:completion]; -} - -- (void)sendAppContentData:(NSData *)data - ExtInfo:(NSString *)info - ExtURL:(NSString *)url - Title:(NSString *)title - Description:(NSString *)description - MessageExt:(NSString *)messageExt - MessageAction:(NSString *)action - InScene:(enum WXScene)scene - MsgSignature:(NSString *)msgSignature - ThumbData:(NSData *)thumbData - ThumbDataHash:(NSString*)thumbDataHash - completion:(void (^ __nullable)(BOOL success))completion { - WXAppExtendObject *ext = [WXAppExtendObject object]; - ext.extInfo = info; - ext.url = url; - ext.fileData = data; - - WXMediaMessage *message = [self messageWithTitle:title - Description:description - Object:ext - MessageExt:messageExt - MessageAction:action - MediaTag:nil - MsgSignature:(msgSignature == (id) [NSNull null]) ? nil : msgSignature - ThumbData:(thumbData == (id) [NSNull null]) ? nil : thumbData - ThumbDataHash:(thumbDataHash == (id) [NSNull null]) ? nil : thumbDataHash - ]; - - SendMessageToWXReq *req = [self requestWithText:nil OrMediaMessage:message bText:NO InScene:scene]; - [WXApi sendReq:req completion:completion]; -} - -- (void)addCardsToCardPackage:(NSArray *)cardIds - cardExts:(NSArray *)cardExts - completion:(void (^ __nullable)(BOOL success))completion { - NSMutableArray *cardItems = [NSMutableArray array]; - for (NSString *cardId in cardIds) { - WXCardItem *item = [[WXCardItem alloc] init]; - item.cardId = cardId; - item.appID = @"wxf8b4f85f3a794e77"; - [cardItems addObject:item]; - } - - for (NSInteger index = 0; index < cardItems.count; index++) { - WXCardItem *item = cardItems[index]; - NSString *ext = cardExts[index]; - item.extMsg = ext; - } - - AddCardToWXCardPackageReq *req = [[AddCardToWXCardPackageReq alloc] init]; - req.cardAry = cardItems; - [WXApi sendReq:req completion:completion]; -} - -- (void)chooseCard:(NSString *)appid - cardSign:(NSString *)cardSign - nonceStr:(NSString *)nonceStr - signType:(NSString *)signType - timestamp:(UInt32)timestamp - completion:(void (^ __nullable)(BOOL success))completion { - WXChooseCardReq *chooseCardReq = [[WXChooseCardReq alloc] init]; - chooseCardReq.appID = appid; - chooseCardReq.cardSign = cardSign; - chooseCardReq.nonceStr = nonceStr; - chooseCardReq.signType = signType; - chooseCardReq.timeStamp = timestamp; - [WXApi sendReq:chooseCardReq completion:completion]; -} - -- (void)sendAuthRequestScope:(NSString *)scope - State:(NSString *)state - OpenID:(NSString *)openID - InViewController:(UIViewController *)viewController - completion:(void (^ __nullable)(BOOL success))completion { - SendAuthReq *req = [[SendAuthReq alloc] init]; - req.scope = scope; // @"post_timeline,sns" - req.state = state; - req.openID = openID; - - return [WXApi sendAuthReq:req - viewController:viewController - delegate:self - completion:completion]; -} - - -- (void)sendAuthRequestScope:(NSString *)scope - State:(NSString *)state - OpenID:(NSString *)openID - NonAutomatic:(BOOL)nonAutomatic - completion:(void (^)(BOOL))completion { - SendAuthReq *req = [[SendAuthReq alloc] init]; - req.scope = scope; // @"post_timeline,sns" - req.state = state; - req.openID = openID; - req.nonautomatic = nonAutomatic; - - [WXApi sendReq:req completion:completion]; - -} - - -- (void)openUrl:(NSString *)url - completion:(void (^ __nullable)(BOOL success))completion { - OpenWebviewReq *req = [[OpenWebviewReq alloc] init]; - req.url = url; - [WXApi sendReq:req completion:completion]; -} - -- (void)chooseInvoice:(NSString *)appid - cardSign:(NSString *)cardSign - nonceStr:(NSString *)nonceStr - signType:(NSString *)signType - timestamp:(UInt32)timestamp - completion:(void (^ __nullable)(BOOL success))completion { - WXChooseInvoiceReq *chooseInvoiceReq = [[WXChooseInvoiceReq alloc] init]; - chooseInvoiceReq.appID = appid; - chooseInvoiceReq.cardSign = cardSign; - chooseInvoiceReq.nonceStr = nonceStr; - chooseInvoiceReq.signType = signType; - // chooseCardReq.cardType = @"INVOICE"; - chooseInvoiceReq.timeStamp = timestamp; - // chooseCardReq.canMultiSelect = 1; - [WXApi sendReq:chooseInvoiceReq completion:completion]; -} - - -- (void)openCustomerService:(NSString *)url CorpId:(NSString *)corpId completion:(void (^)(BOOL))completion { - WXOpenCustomerServiceReq *req = [[WXOpenCustomerServiceReq alloc] init]; - req.corpid = corpId; //企业ID - req.url = url; //客服URL - [WXApi sendReq:req completion:completion]; -} - -- (void)handleAuthByPhoneLogin:(FlutterMethodCall *)call result:(FlutterResult)result { - UIViewController *vc = UIApplication.sharedApplication.keyWindow.rootViewController; - SendAuthReq *authReq = [[SendAuthReq alloc] init]; - authReq.scope = call.arguments[@"scope"]; - authReq.state = (call.arguments[@"state"] == (id) [NSNull null]) ? nil : call.arguments[@"state"]; - [WXApi sendAuthReq:authReq viewController:vc delegate:self completion:^(BOOL success) { - result(@(success)); - }]; -} - -- (void)handleAuth:(FlutterMethodCall *)call result:(FlutterResult)result { - NSString *openId = call.arguments[@"openId"]; - - [self sendAuthRequestScope:call.arguments[@"scope"] - State:(call.arguments[@"state"] == (id) [NSNull null]) ? nil : call.arguments[@"state"] - OpenID:(openId == (id) [NSNull null]) ? nil : openId - NonAutomatic:[call.arguments[@"nonAutomatic"] boolValue] - completion:^(BOOL done) { - result(@(done)); - }]; -} - -- (void)authByQRCode:(FlutterMethodCall *)call result:(FlutterResult)result { - NSString *appId = call.arguments[@"appId"]; - NSString *scope = call.arguments[@"scope"]; - NSString *nonceStr = call.arguments[@"nonceStr"]; - NSString *timeStamp = call.arguments[@"timeStamp"]; - NSString *signature = call.arguments[@"signature"]; - NSString *schemeData = (call.arguments[@"schemeData"] == (id) [NSNull null]) ? nil : call.arguments[@"schemeData"]; - - BOOL done = [_qrauth Auth:appId nonceStr:nonceStr timeStamp:timeStamp scope:scope signature:signature schemeData:schemeData]; - result(@(done)); -} - -- (void)stopAuthByQRCode:(FlutterMethodCall *)call result:(FlutterResult)result { - BOOL done = [_qrauth StopAuth]; - result(@(done)); -} - -- (void)onQrcodeScanned { - if (_channel != nil) { - [_channel invokeMethod:@"onQRCodeScanned" arguments:@{@"errCode": @0}]; - } -} - -- (void)onAuthGotQrcode:(UIImage *)image { - NSData *imageData = UIImagePNGRepresentation(image); - // if (imageData == nil) { - // imageData = UIImageJPEGRepresentation(image, 1); - // } - if (_channel != nil) { - [_channel invokeMethod:@"onAuthGotQRCode" arguments:@{@"errCode": @0, @"qrCode": imageData}]; - } -} - -- (void)onAuthFinish:(int)errCode AuthCode:(nullable NSString *)authCode { - NSDictionary *errorCode = @{@"errCode": @(errCode)}; - NSMutableDictionary *result = [NSMutableDictionary dictionaryWithDictionary:errorCode]; - if (authCode != nil) { - result[@"authCode"] = authCode; - } - if (_channel != nil) { - [_channel invokeMethod:@"onAuthByQRCodeFinished" arguments:result]; - } -} - -- (WXMediaMessage *)messageWithTitle:(NSString *)title - Description:(NSString *)description - Object:(id)mediaObject - MessageExt:(NSString *)messageExt - MessageAction:(NSString *)action - MediaTag:(NSString *)tagName - MsgSignature:(NSString *)msgSignature - ThumbData:(NSData *)thumbData - ThumbDataHash:(NSString*)thumbDataHash { - WXMediaMessage *message = [WXMediaMessage message]; - message.title = title; - message.description = description; - message.mediaObject = mediaObject; - message.messageExt = messageExt; - message.messageAction = action; - message.mediaTagName = tagName; - message.thumbData = thumbData; - message.thumbDataHash = thumbDataHash; - if (msgSignature != nil) { - message.msgSignature = msgSignature; - } - return message; -} - -- (SendMessageToWXReq *)requestWithText:(NSString *)text - OrMediaMessage:(WXMediaMessage *)message - bText:(BOOL)bText - InScene:(enum WXScene)scene { - SendMessageToWXReq *req = [[SendMessageToWXReq alloc] init]; - req.bText = bText; - req.scene = scene; - if (bText) { - req.text = text; - } else { - req.message = message; - } - return req; -} - -- (NSString*)fetchWeChatAppId { - NSDictionary *infoDict = [[NSBundle mainBundle] infoDictionary]; - NSArray *types = infoDict[@"CFBundleURLTypes"]; - for (NSDictionary *dict in types) { - if ([@"weixin" isEqualToString:dict[@"CFBundleURLName"]]) { - return dict[@"CFBundleURLSchemes"][0]; - } - } - return nil; -} - -@end diff --git a/ios/Classes/FluwxStringUtil.h b/ios/Classes/FluwxStringUtil.h deleted file mode 100644 index 35f49f2e..00000000 --- a/ios/Classes/FluwxStringUtil.h +++ /dev/null @@ -1,12 +0,0 @@ -// -// Created by mo on 2020/3/7. -// - -#import - - -@interface FluwxStringUtil : NSObject -+ (BOOL)isBlank:(NSString *)string; - -+ (NSString *)nilToEmpty:(NSString *)string; -@end \ No newline at end of file diff --git a/ios/Classes/FluwxStringUtil.m b/ios/Classes/FluwxStringUtil.m deleted file mode 100644 index ba4fa709..00000000 --- a/ios/Classes/FluwxStringUtil.m +++ /dev/null @@ -1,24 +0,0 @@ -// -// Created by mo on 2020/3/7. -// - -#import - - -@implementation FluwxStringUtil - -+ (BOOL)isBlank:(NSString *)string { - if (string == nil) { - return YES; - } - if ([string isKindOfClass:[NSNull class]]) { - return YES; - } - return [[string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] length] == 0; -} - -+ (NSString *)nilToEmpty:(NSString *)string { - return string == nil ? @"" : string; -} - -@end diff --git a/ios/Classes/NSStringWrapper.h b/ios/Classes/NSStringWrapper.h deleted file mode 100644 index bfd571b7..00000000 --- a/ios/Classes/NSStringWrapper.h +++ /dev/null @@ -1,64 +0,0 @@ -// -// Created by mo on 2020/3/8. -// - - -#import - -#define JavaNotFound -1 - -@interface NSString (Wrapper) - -/** Return the char value at the specified index. */ -- (unichar)charAt:(int)index; - -/** - * Compares two strings lexicographically. - * the value 0 if the argument string is equal to this string; - * a value less than 0 if this string is lexicographically less than the string argument; - * and a value greater than 0 if this string is lexicographically greater than the string argument. - */ -- (int)compareTo:(NSString *)anotherString; - -- (int)compareToIgnoreCase:(NSString *)str; - -- (BOOL)contains:(NSString *)str; - -- (BOOL)startsWith:(NSString *)prefix; - -- (BOOL)endsWith:(NSString *)suffix; - -- (BOOL)equals:(NSString *)anotherString; - -- (BOOL)equalsIgnoreCase:(NSString *)anotherString; - -- (int)indexOfChar:(unichar)ch; - -- (int)indexOfChar:(unichar)ch fromIndex:(int)index; - -- (int)indexOfString:(NSString *)str; - -- (int)indexOfString:(NSString *)str fromIndex:(int)index; - -- (int)lastIndexOfChar:(unichar)ch; - -- (int)lastIndexOfChar:(unichar)ch fromIndex:(int)index; - -- (int)lastIndexOfString:(NSString *)str; - -- (int)lastIndexOfString:(NSString *)str fromIndex:(int)index; - -- (NSString *)substringFromIndex:(NSInteger)beginIndex - toIndex:(NSInteger)endIndex; - -- (NSString *)toLowerCase; - -- (NSString *)toUpperCase; - -- (NSString *)trim; - -- (NSString *)replaceAll:(NSString *)origin with:(NSString *)replacement; - -- (NSArray *)split:(NSString *)separator; - -@end diff --git a/ios/Classes/NSStringWrapper.m b/ios/Classes/NSStringWrapper.m deleted file mode 100644 index ce88914b..00000000 --- a/ios/Classes/NSStringWrapper.m +++ /dev/null @@ -1,153 +0,0 @@ -// -// Created by mo on 2020/3/8. -// - -#import - -@implementation NSString (Wrapper) - - -/** Java-like method. Returns the char value at the specified index. */ -- (unichar)charAt:(int)index { - return [self characterAtIndex:index]; -} - -/** - * Java-like method. Compares two strings lexicographically. - * the value 0 if the argument string is equal to this string; - * a value less than 0 if this string is lexicographically less than the string argument; - * and a value greater than 0 if this string is lexicographically greater than the string argument. - */ -- (int)compareTo:(NSString *)anotherString { - return (int)[self compare:anotherString]; -} - -/** Java-like method. Compares two strings lexicographically, ignoring case differences. */ -- (int)compareToIgnoreCase:(NSString *)str { - return (int)[self compare:str options:NSCaseInsensitiveSearch]; -} - -/** Java-like method. Returns true if and only if this string contains the specified sequence of char values. */ -- (BOOL)contains:(NSString *)str { - NSRange range = [self rangeOfString:str]; - return (range.location != NSNotFound); -} - -- (BOOL)startsWith:(NSString *)prefix { - return [self hasPrefix:prefix]; -} - -- (BOOL)endsWith:(NSString *)suffix { - return [self hasSuffix:suffix]; -} - -- (BOOL)equals:(NSString *)anotherString { - return [self isEqualToString:anotherString]; -} - -- (BOOL)equalsIgnoreCase:(NSString *)anotherString { - return [[self toLowerCase] equals:[anotherString toLowerCase]]; -} - -- (int)indexOfChar:(unichar)ch { - return [self indexOfChar:ch fromIndex:0]; -} - -- (int)indexOfChar:(unichar)ch fromIndex:(int)index { - int len = (int)self.length; - for (int i = index; i < len; ++i) { - if (ch == [self charAt:i]) { - return i; - } - } - return JavaNotFound; -} - -- (int)indexOfString:(NSString *)str { - NSRange range = [self rangeOfString:str]; - if (range.location == NSNotFound) { - return JavaNotFound; - } - return (int)range.location; -} - -- (int)indexOfString:(NSString *)str fromIndex:(int)index { - NSRange fromRange = NSMakeRange(index, self.length - index); - NSRange range = [self rangeOfString:str options:NSLiteralSearch range:fromRange]; - if (range.location == NSNotFound) { - return JavaNotFound; - } - return (int)range.location; -} - -- (int)lastIndexOfChar:(unichar)ch { - int len = (int)self.length; - for (int i = len - 1; i >= 0; --i) { - if ([self charAt:i] == ch) { - return i; - } - } - return JavaNotFound; -} - -- (int)lastIndexOfChar:(unichar)ch fromIndex:(int)index { - int len = (int)self.length; - if (index >= len) { - index = len - 1; - } - for (int i = index; i >= 0; --i) { - if ([self charAt:i] == ch) { - return index; - } - } - return JavaNotFound; -} - -- (int)lastIndexOfString:(NSString *)str { - NSRange range = [self rangeOfString:str options:NSBackwardsSearch]; - if (range.location == NSNotFound) { - return JavaNotFound; - } - return (int)range.location; -} - -- (int)lastIndexOfString:(NSString *)str fromIndex:(int)index { - NSRange fromRange = NSMakeRange(0, index); - NSRange range = [self rangeOfString:str options:NSBackwardsSearch range:fromRange]; - if (range.location == NSNotFound) { - return JavaNotFound; - } - return (int)range.location; -} - -- (NSString *)substringFromIndex:(NSInteger)beginIndex - toIndex:(NSInteger)endIndex { - if (endIndex <= beginIndex) { - return @""; - } - NSRange range = NSMakeRange(beginIndex, endIndex - beginIndex); - return [self substringWithRange:range]; -} - -- (NSString *)toLowerCase { - return [self lowercaseString]; -} - -- (NSString *)toUpperCase { - return [self uppercaseString]; -} - -- (NSString *)trim { - return [self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; -} - -- (NSString *)replaceAll:(NSString *)origin with:(NSString *)replacement { - return [self stringByReplacingOccurrencesOfString:origin withString:replacement]; -} - -- (NSArray *)split:(NSString *)separator { - return [self componentsSeparatedByString:separator]; -} - - -@end diff --git a/ios/Classes/ThumbnailHelper.h b/ios/Classes/ThumbnailHelper.h deleted file mode 100644 index 0a1fe918..00000000 --- a/ios/Classes/ThumbnailHelper.h +++ /dev/null @@ -1,17 +0,0 @@ -// -// Created by mo on 2020/3/7. -// - -#import - - -@interface ThumbnailHelper : NSObject - -+ (UIImage *)compressImage:(UIImage *)image toByte:(NSUInteger)maxLength isPNG:(BOOL)isPNG; - -/// NSData 压缩后转NSData -/// @param imageData 来源data -/// @param maxLength 压缩目标值,压缩结果在maxLength的0.9~1之间 -+ (NSData *)compressImageData:(NSData *)imageData toByte:(NSUInteger)maxLength; - -@end diff --git a/ios/Classes/ThumbnailHelper.m b/ios/Classes/ThumbnailHelper.m deleted file mode 100644 index 744afb04..00000000 --- a/ios/Classes/ThumbnailHelper.m +++ /dev/null @@ -1,134 +0,0 @@ -// -// Created by mo on 2020/3/7. -// - -#import "ThumbnailHelper.h" - - -@implementation ThumbnailHelper - -+ (NSData *)compressImageData:(NSData *)imageData toByte:(NSUInteger)maxLength { - // Compress by quality - CGFloat compression = 1; - NSData *data = imageData; - NSLog(@"压缩前 %lu %lu", (unsigned long)data.length,maxLength); - if (data.length < maxLength) return data; - - UIImage *image = [UIImage imageWithData:imageData]; - CGFloat max = 1; - CGFloat min = 0; - for (int i = 0; i < 6; ++i) { - compression = (max + min) / 2; - data = UIImageJPEGRepresentation(image, compression); - if (data.length < maxLength * 0.9) { - min = compression; - } else if (data.length > maxLength) { - max = compression; - } else { - break; - } - } - - NSLog(@"压缩第一次 %lu %lu", (unsigned long)data.length,maxLength); - if (data.length < maxLength) return data; - - UIImage *resultImage; - - resultImage = [UIImage imageWithData:data]; - - // Compress by size - NSUInteger lastDataLength = 0; - while (data.length > maxLength && data.length != lastDataLength) { - lastDataLength = data.length; - CGFloat ratio = (CGFloat) maxLength / data.length; - CGSize size = CGSizeMake((NSUInteger) (resultImage.size.width * sqrtf(ratio)), - (NSUInteger) (resultImage.size.height * sqrtf(ratio))); // Use NSUInteger to prevent white blank - UIGraphicsBeginImageContext(size); - [resultImage drawInRect:CGRectMake(0, 0, size.width, size.height)]; - resultImage = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); - data = UIImageJPEGRepresentation(resultImage, compression); - } - - NSLog(@"压缩第二次 %lu %lu", (unsigned long)data.length,maxLength); - return data; -} - -+ (UIImage *)compressImage:(UIImage *)image toByte:(NSUInteger)maxLength isPNG:(BOOL)isPNG { - // Compress by quality - CGFloat compression = 1; - NSData *data = UIImageJPEGRepresentation(image, compression); - if (data.length < maxLength) return image; - - CGFloat max = 1; - CGFloat min = 0; - for (int i = 0; i < 6; ++i) { - compression = (max + min) / 2; - data = UIImageJPEGRepresentation(image, compression); - if (data.length < maxLength * 0.9) { - min = compression; - } else if (data.length > maxLength) { - max = compression; - } else { - break; - } - } - - UIImage *resultImage; - if (isPNG) { - NSData *tmp = UIImagePNGRepresentation([UIImage imageWithData:data]); - resultImage = [UIImage imageWithData:tmp]; - } else { - resultImage = [UIImage imageWithData:data]; - } - - - if (data.length < maxLength) return resultImage; - - // Compress by size - NSUInteger lastDataLength = 0; - while (data.length > maxLength && data.length != lastDataLength) { - lastDataLength = data.length; - CGFloat ratio = (CGFloat) maxLength / data.length; - CGSize size = CGSizeMake((NSUInteger) (resultImage.size.width * sqrtf(ratio)), - (NSUInteger) (resultImage.size.height * sqrtf(ratio))); // Use NSUInteger to prevent white blank - UIGraphicsBeginImageContext(size); - [resultImage drawInRect:CGRectMake(0, 0, size.width, size.height)]; - resultImage = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); - data = UIImageJPEGRepresentation(resultImage, compression); - } - - return resultImage; -} - - -- (UIImage *)scaleFromImage:(UIImage *)image width:(CGSize)newSize { - CGSize imageSize = image.size; - CGFloat width = imageSize.width; - CGFloat height = imageSize.height; - - if (width <= newSize.width && height <= newSize.height) { - return image; - } - - if (width == 0 || height == 0) { - return image; - } - - CGFloat widthFactor = newSize.width / width; - CGFloat heightFactor = newSize.height / height; - CGFloat scaleFactor = (widthFactor < heightFactor ? widthFactor : heightFactor); - - CGFloat scaledWidth = width * scaleFactor; - CGFloat scaledHeight = height * scaleFactor; - CGSize targetSize = CGSizeMake(scaledWidth, scaledHeight); - - UIGraphicsBeginImageContext(targetSize); - [image drawInRect:CGRectMake(0, 0, scaledWidth, scaledHeight)]; - UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); - return newImage; -} - -@end diff --git a/ios/Classes/public/FluwxDelegate.h b/ios/Classes/public/FluwxDelegate.h deleted file mode 100644 index fa9d1df0..00000000 --- a/ios/Classes/public/FluwxDelegate.h +++ /dev/null @@ -1,19 +0,0 @@ -// -// FluwxDelegate.h -// Pods -// -// Created by Mo on 2022/3/6. -// -#import - -@interface FluwxDelegate : NSObject - -@property (strong,nonatomic)NSString *extMsg; - -@property (strong,nonatomic)NSString *extData; - -+ (instancetype)defaultManager; - -- (void)registerWxAPI:(NSString *)appId universalLink:(NSString *)universalLink; - -@end diff --git a/ios/Classes/public/FluwxPlugin.h b/ios/Classes/public/FluwxPlugin.h deleted file mode 100644 index 4b60454e..00000000 --- a/ios/Classes/public/FluwxPlugin.h +++ /dev/null @@ -1,4 +0,0 @@ -#import - -@interface FluwxPlugin : NSObject -@end diff --git a/ios/Resources/PrivacyInfo.xcprivacy b/ios/Resources/PrivacyInfo.xcprivacy deleted file mode 100644 index 80f7c45e..00000000 --- a/ios/Resources/PrivacyInfo.xcprivacy +++ /dev/null @@ -1,23 +0,0 @@ - - - - - NSPrivacyTrackingDomains - - NSPrivacyAccessedAPITypes - - - NSPrivacyAccessedAPITypeReasons - - CA92.1 - - NSPrivacyAccessedAPIType - NSPrivacyAccessedAPICategoryUserDefaults - - - NSPrivacyCollectedDataTypes - - NSPrivacyTracking - - - diff --git a/ios/fluwx.podspec b/ios/fluwx.podspec deleted file mode 100644 index de4e3b54..00000000 --- a/ios/fluwx.podspec +++ /dev/null @@ -1,121 +0,0 @@ -# -# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. -# Run `pod lib lint fluwx.podspec` to validate before publishing. -# - -# -# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. -# Run `pod lib lint fluwx.podspec` to validate before publishing. -# - -pubspec = YAML.load_file(File.join('..', 'pubspec.yaml')) -library_version = pubspec['version'].gsub('+', '-') - -current_dir = Dir.pwd -calling_dir = File.dirname(__FILE__) -project_dir = calling_dir.slice(0..(calling_dir.index('/.symlinks'))) -symlinks_index = calling_dir.index('/ios/.symlinks') -if !symlinks_index - symlinks_index = calling_dir.index('/.ios/.symlinks') -end - -flutter_project_dir = calling_dir.slice(0..(symlinks_index)) - -Pod::UI.puts "[fluwx] #{Psych::VERSION}" -psych_version_gte_500 = Gem::Version.new(Psych::VERSION) >= Gem::Version.new('5.0.0') -if psych_version_gte_500 == true - cfg = YAML.load_file(File.join(flutter_project_dir, 'pubspec.yaml'), aliases: true) -else - cfg = YAML.load_file(File.join(flutter_project_dir, 'pubspec.yaml')) -end - -logging_status = "WECHAT_LOGGING=0" - -if cfg['fluwx'] && cfg['fluwx']['debug_logging'] == true - logging_status = 'WECHAT_LOGGING=1' -else - logging_status = 'WECHAT_LOGGING=0' -end - - -if cfg['fluwx'] && cfg['fluwx']['ios'] && cfg['fluwx']['ios']['no_pay'] == true - fluwx_subspec = 'no_pay' -else - fluwx_subspec = 'pay' -end -Pod::UI.puts "[fluwx] Using SDK with #{fluwx_subspec}" - -app_id = '' -if cfg['fluwx'] && cfg['fluwx']['app_id'] - app_id = cfg['fluwx']['app_id'] -end -if !app_id.nil? && !app_id.empty? - Pod::UI.puts "[fluwx] app_id: #{app_id}" -end - -ignore_security = '' -if cfg['fluwx'] && cfg['fluwx']['ios'] && cfg['fluwx']['ios']['ignore_security'] == true - ignore_security = '-i' -end -if !ignore_security.nil? && !ignore_security.empty? - Pod::UI.puts "[fluwx] ignore_security: #{ignore_security}" -end - -universal_link = '' -if cfg['fluwx'] && (cfg['fluwx']['ios'] && cfg['fluwx']['ios']['universal_link']) - universal_link = cfg['fluwx']['ios']['universal_link'] -end -if !universal_link.nil? && !universal_link.empty? - Pod::UI.puts "[fluwx] universal_link: #{universal_link}" -end - -command = "ruby #{current_dir}/wechat_setup.rb #{ignore_security}" -command += " -p #{project_dir} -n Runner.xcodeproj" -command += " -a #{app_id}" unless app_id.nil? || app_id.empty? -command += " -u #{universal_link}" unless universal_link.nil? || universal_link.empty? -system(command) - -Pod::Spec.new do |s| - s.name = 'fluwx' - s.version = '0.0.1' - s.summary = 'The capability of implementing WeChat SDKs in Flutter. With Fluwx, developers can use WeChatSDK easily, such as sharing, payment, lanuch mini program and etc.' - s.description = <<-DESC -The capability of implementing WeChat SDKs in Flutter. With Fluwx, developers can use WeChatSDK easily, such as sharing, payment, lanuch mini program and etc. - 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.platform = :ios, '12.0' - s.static_framework = true - s.resource_bundles = {'fluwx_privacy' => ['Resources/PrivacyInfo.xcprivacy']} - s.default_subspec = fluwx_subspec - s.swift_version = '5.0' - - pod_target_xcconfig = { - 'OTHER_LDFLAGS' => '$(inherited) -ObjC -all_load' - } - - s.subspec 'pay' do |sp| - sp.dependency 'WechatOpenSDK-XCFramework','~> 2.0.5' - - pod_target_xcconfig["GCC_PREPROCESSOR_DEFINITIONS"] = "$(inherited) #{logging_status}" - - sp.pod_target_xcconfig = pod_target_xcconfig - - end - - s.subspec 'no_pay' do |sp| - sp.dependency 'OpenWeChatSDKNoPay','~> 2.0.5' - sp.frameworks = 'CoreGraphics', 'Security', 'WebKit' - sp.libraries = 'c++', 'z', 'sqlite3.0' - pod_target_xcconfig["GCC_PREPROCESSOR_DEFINITIONS"] = "$(inherited) NO_PAY=1 #{logging_status}" - sp.pod_target_xcconfig = pod_target_xcconfig - end - - # Flutter.framework does not contain a i386 slice. - s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' } -end diff --git a/ios/wechat_setup.rb b/ios/wechat_setup.rb deleted file mode 100644 index 364c7d18..00000000 --- a/ios/wechat_setup.rb +++ /dev/null @@ -1,168 +0,0 @@ -# -# Reference documentations -# https://github.com/firebase/flutterfire/blob/master/packages/firebase_crashlytics/firebase_crashlytics/ios/crashlytics_add_upload_symbols -# https://github.com/MagicalWater/Base-APP-Env/blob/master/fastlane/actions/xcode_parse.rb -# - -require 'xcodeproj' -require 'plist' -require 'optparse' -require 'uri' - -# Dictionary to hold command line arguments -options_dict = {} - -# Parse command line arguments into options_dict -OptionParser.new do |options| - options.banner = "Setup the Wechat to an Xcode target." - - options.on("-p", "--projectDirectory=DIRECTORY", String, "Directory of the Xcode project") do |dir| - options_dict[:project_dir] = dir - end - - options.on("-n", "--projectName=NAME", String, "Name of the Xcode project (ex: Runner.xcodeproj)") do |name| - options_dict[:project_name] = name - end - - options.on("-i", "--ignoreSecurity", "Ignore modifying NSAppTransportSecurity") do |opts| - options_dict[:ignore_security] = true - end - - options.on("-a", "--appId=APPID", String, "App ID for Wechat") do |opts| - options_dict[:app_id] = opts - end - - options.on("-u", "--universalLink=UNIVERSALLINK", String, "Universal Link for Wechat") do |opts| - options_dict[:universal_link] = opts - end -end.parse! - -# Minimum required arguments are a project directory and project name -unless (options_dict[:project_dir] and options_dict[:project_name]) - abort("Must provide a project directory and project name.\n") -end - -# Path to the Xcode project to modify -project_path = File.join(options_dict[:project_dir], options_dict[:project_name]) - -unless (File.exist?(project_path)) - abort("Project at #{project_path} does not exist. Please check paths manually.\n"); -end - -# Actually open and modify the project -project = Xcodeproj::Project.open(project_path) -project.targets.each do |target| - if target.name == "Runner" - app_id = options_dict[:app_id] - universal_link = options_dict[:universal_link] - - applinks = nil - if (!app_id.nil? && !app_id.empty? && !universal_link.nil? && !universal_link.empty?) - begin - applinks = "applinks:#{URI.parse(universal_link).host}" - rescue URI::InvalidURIError - applinks = nil - end - end - - sectionObject = {} - project.objects.each do |object| - if object.uuid == target.uuid - sectionObject = object - break - end - end - sectionObject.build_configurations.each do |config| - infoplist = config.build_settings["INFOPLIST_FILE"] - if !infoplist - abort("INFOPLIST_FILE is not exist\n") - end - infoplistFile = File.join(options_dict[:project_dir], infoplist) - if !File.exist?(infoplistFile) - abort("#{infoplist} is not exist\n") - end - result = Plist.parse_xml(infoplistFile, marshal: false) - if !result - result = {} - end - urlTypes = result["CFBundleURLTypes"] - if !urlTypes - urlTypes = [] - result["CFBundleURLTypes"] = urlTypes - end - isUrlTypeExist = urlTypes.any? { |urlType| urlType["CFBundleURLSchemes"] && (urlType["CFBundleURLSchemes"].include? app_id) } - if !app_id.nil? && !app_id.empty? && !isUrlTypeExist - print("writing app id\n ") - urlTypes << { - "CFBundleTypeRole": "Editor", - "CFBundleURLName": "weixin", - "CFBundleURLSchemes": [ app_id ] - } - File.write(infoplistFile, Plist::Emit.dump(result)) - end - - queriesSchemes = result["LSApplicationQueriesSchemes"] - if !queriesSchemes - queriesSchemes = [] - result["LSApplicationQueriesSchemes"] = queriesSchemes - end - wechatQueriesSchemes = ["weixin", "weixinULAPI", "weixinURLParamsAPI"] - if wechatQueriesSchemes.any? { |queriesScheme| !(queriesSchemes.include? queriesScheme) } - wechatQueriesSchemes.each do |queriesScheme| - if !(queriesSchemes.include? queriesScheme) - queriesSchemes << queriesScheme - end - end - File.write(infoplistFile, Plist::Emit.dump(result)) - end - if !options_dict[:ignore_security] - security = result["NSAppTransportSecurity"] - if !security - security = {} - result["NSAppTransportSecurity"] = security - end - if security["NSAllowsArbitraryLoads"] != true - security["NSAllowsArbitraryLoads"] = true - File.write(infoplistFile, Plist::Emit.dump(result)) - end - if security["NSAllowsArbitraryLoadsInWebContent"] != true - security["NSAllowsArbitraryLoadsInWebContent"] = true - File.write(infoplistFile, Plist::Emit.dump(result)) - end - end - end - sectionObject.build_configurations.each do |config| - codeSignEntitlements = config.build_settings["CODE_SIGN_ENTITLEMENTS"] - if !codeSignEntitlements - codeSignEntitlements = "Runner/Runner.entitlements" - config.build_settings["CODE_SIGN_ENTITLEMENTS"] = codeSignEntitlements - project.save() - end - codeSignEntitlementsFile = File.join(options_dict[:project_dir], codeSignEntitlements) - if !File.exist?(codeSignEntitlementsFile) - content = Plist::Emit.dump({}) - File.write(codeSignEntitlementsFile, content) - end - runnerTargetMainGroup = project.main_group.find_subpath('Runner', false) - isRefExist = runnerTargetMainGroup.files.any? { |file| file.path.include? File.basename(codeSignEntitlementsFile) } - if !isRefExist - runnerTargetMainGroup.new_reference(File.basename(codeSignEntitlementsFile)) - project.save() - end - result = Plist.parse_xml(codeSignEntitlementsFile, marshal: false) - if !result - result = {} - end - domains = result["com.apple.developer.associated-domains"] - if !domains - domains = [] - result["com.apple.developer.associated-domains"] = domains - end - isApplinksExist = domains.include? applinks - if !isApplinksExist && !applinks.nil? - domains << applinks - File.write(codeSignEntitlementsFile, Plist::Emit.dump(result)) - end - end - end -end diff --git a/ohos/.gitignore b/ohos/.gitignore deleted file mode 100644 index 09c15d8f..00000000 --- a/ohos/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -/node_modules -/oh_modules -/.preview -/.idea -/build -/.cxx -/.test -/BuildProfile.ets -/oh-package-lock.json5 -*.har \ No newline at end of file diff --git a/ohos/build-profile.json5 b/ohos/build-profile.json5 deleted file mode 100644 index 79961f96..00000000 --- a/ohos/build-profile.json5 +++ /dev/null @@ -1,10 +0,0 @@ -{ - "apiType": "stageMode", - "buildOption": { - }, - "targets": [ - { - "name": "default" - } - ] -} diff --git a/ohos/hvigorfile.ts b/ohos/hvigorfile.ts deleted file mode 100644 index 47e6e1f8..00000000 --- a/ohos/hvigorfile.ts +++ /dev/null @@ -1,2 +0,0 @@ -// Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently. -export { harTasks } from '@ohos/hvigor-ohos-plugin'; \ No newline at end of file diff --git a/ohos/index.ets b/ohos/index.ets deleted file mode 100644 index d6659ad4..00000000 --- a/ohos/index.ets +++ /dev/null @@ -1,17 +0,0 @@ -/* -* Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd. -* 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. -*/ - -import FluwxPlugin from './src/main/ets/components/plugin/FluwxPlugin'; -export default FluwxPlugin; diff --git a/ohos/local.properties b/ohos/local.properties deleted file mode 100644 index e3bd5ec5..00000000 --- a/ohos/local.properties +++ /dev/null @@ -1 +0,0 @@ -hwsdk.dir=/Applications/DevEco-Studio.app/Contents/sdk \ No newline at end of file diff --git a/ohos/oh-package.json5 b/ohos/oh-package.json5 deleted file mode 100644 index 07abd25a..00000000 --- a/ohos/oh-package.json5 +++ /dev/null @@ -1,12 +0,0 @@ -{ - "name": "fluwx", - "version": "1.0.0", - "description": "Please describe the basic information.", - "main": "index.ets", - "author": "", - "license": "Apache-2.0", - "dependencies": { - "@ohos/flutter_ohos": "file:./har/flutter.har", - "@tencent/wechat_open_sdk": "1.0.15" - } -} diff --git a/ohos/src/main/ets/components/plugin/FluwxPlugin.ets b/ohos/src/main/ets/components/plugin/FluwxPlugin.ets deleted file mode 100644 index a7996ad7..00000000 --- a/ohos/src/main/ets/components/plugin/FluwxPlugin.ets +++ /dev/null @@ -1,299 +0,0 @@ -import { - AbilityAware, - AbilityPluginBinding, - FlutterPlugin, - FlutterPluginBinding, - MethodCall, - MethodCallHandler, - MethodChannel, - MethodResult, - NewWantListener, -} from '@ohos/flutter_ohos'; -import * as wechatSDK from "@tencent/wechat_open_sdk" -import { FluwxAuthHandler } from './handlers/FluwxAuthHandler'; -import { AbilityConstant, common, Want } from '@kit.AbilityKit'; -import { WXAPiHandler } from './handlers/WXAPiHandler'; -import { FluwxShareHandler } from './handlers/FluwxShareHandler'; - -const MESSAGE_CHANNEL_NAME = "com.jarvanmo/fluwx" -const KEY_ERR_STR = "errStr" -const KEY_ERR_CODE = "errCode" -const KEY_OPEN_ID = "openId" -const KEY_TYPE = "type" - -/** FluwxPlugin **/ -export default class FluwxPlugin implements FlutterPlugin, MethodCallHandler, AbilityAware, NewWantListener, wechatSDK.WXApiEventHandler { - private channel: MethodChannel | null = null; - private appContext: common.Context | null = null; - private uiContext: common.UIAbilityContext | null = null; - private binding: AbilityPluginBinding | null = null - private authHandler: FluwxAuthHandler | null = null; - private shareHandler: FluwxShareHandler | null = null; - private extMsg: string | null = null; - - getUniqueClassName(): string { - return "FluwxPlugin" - } - - onAttachedToEngine(binding: FlutterPluginBinding): void { - this.channel = new MethodChannel(binding.getBinaryMessenger(), MESSAGE_CHANNEL_NAME); - this.channel.setMethodCallHandler(this) - this.appContext = binding.getApplicationContext(); - this.authHandler = new FluwxAuthHandler(this.channel); - this.shareHandler = new FluwxShareHandler(); - } - - onDetachedFromEngine(binding: FlutterPluginBinding): void { - this.channel = null; - this.appContext = null; - this.authHandler = null; - this.shareHandler = null; - } - - onAttachedToAbility(binding: AbilityPluginBinding): void { - this.binding = binding - this.uiContext = binding.getAbility().context; - WXAPiHandler.setContext(this.uiContext); - binding.addOnNewWantListener(this) - } - - onDetachedFromAbility(): void { - this.binding?.removeOnNewWantListener(this) - this.binding = null - this.uiContext = null; - } - - onMethodCall(call: MethodCall, result: MethodResult): void { - if (call.method.startsWith("share")) { - this.shareHandler?.share(call, result); - return; - } - - switch (call.method) { - case "isWeChatInstalled": - WXAPiHandler.checkWeChatInstallation(result); - break; - case "registerApp": - WXAPiHandler.registerApp(call, result); - break; - case "sendAuth": - this.authHandler?.sendAuth(call, result); - break; - case "authByQRCode": - this.authHandler?.authByQRCode(call, result); - break; - case "stopAuthByQRCode": - this.authHandler?.stopAuthByQRCode(result); - break; - case "payWithFluwx": - this.handlePay(call, result); - break; - case "payWithHongKongWallet": - // TODO - result.notImplemented(); - break; - case "launchMiniProgram": - this.launchMiniProgram(call, result); - break; - case "subscribeMsg": - // TODO - result.notImplemented(); - break; - case "autoDeduct": - // TODO - result.notImplemented(); - break; - case "autoDeductV2": - // TODO - result.notImplemented(); - break; - case "openWXApp": - result.success(WXAPiHandler.wxApi?.openWechat(this.uiContext)); - break; - case "getExtMsg": - result.success(this.extMsg); - this.extMsg = null; - break; - case "openWeChatCustomerServiceChat": - this.openWeChatCustomerServiceChat(call, result); - break; - case "checkSupportOpenBusinessView": - WXAPiHandler.checkSupportOpenBusinessView(result); - break; - case "openBusinessView": - this.openBusinessView(call, result); - break; - case "openWeChatInvoice": - // TODO - result.notImplemented(); - break; - case "openUrl": - // TODO - result.notImplemented(); - break; - case "openRankList": - // TODO - result.notImplemented(); - break; - case "attemptToResumeMsgFromWx": - this.attemptToResumeMsgFromWx(result); - break; - case "selfCheck": - result.success(null) - break; - default: - result.notImplemented(); - } - } - - onNewWant(want: Want, launchParams: AbilityConstant.LaunchParam): void { - WXAPiHandler.wxApi?.handleWant(want, this); - } - - // 微信回调 start - - onReq = (req: wechatSDK.BaseReq): void => { - if (req instanceof wechatSDK.LaunchFromWXReq) { - const _result: Map = new Map(); - _result.set("extMsg", req.message?.messageExt); - _result.set("messageAction", req.message?.messageAction); - _result.set("lang", req.lang); - _result.set("country", req.country); - this.channel?.invokeMethod("onWXLaunchFromWX", _result); - } - } - - onResp = (resp: wechatSDK.BaseResp): void => { - if (resp instanceof wechatSDK.SendAuthResp) { - this.onAuthResponse(resp); - return; - } - - if (resp instanceof wechatSDK.SendMessageToWXResp) { - this.onSendMessageToWXResp(resp); - return; - } - - if (resp instanceof wechatSDK.PayResp) { - this.onPayResp(resp); - return; - } - - if (resp instanceof wechatSDK.LaunchMiniProgramResp) { - this.onLaunchMiniProgramResp(resp); - return; - } - } - - // 微信回调 end - - onAuthResponse(resp: wechatSDK.SendAuthResp) { - const result: Map = new Map(); - result.set(KEY_ERR_CODE, resp.errCode); - result.set(KEY_ERR_STR, resp.errStr); - result.set("code", resp.code); - result.set("state", resp.state); - result.set("lang", resp.lang); - result.set("country", resp.country); - result.set(KEY_OPEN_ID, resp.openId); - result.set("url", resp.url); - result.set(KEY_TYPE, resp.type); - - this.channel?.invokeMethod("onAuthResponse", result); - } - - onSendMessageToWXResp(resp: wechatSDK.SendMessageToWXResp) { - const _result: Map = new Map(); - _result.set(KEY_ERR_CODE, resp.errCode); - _result.set(KEY_ERR_STR, resp.errStr); - _result.set(KEY_TYPE, resp.type); - _result.set(KEY_OPEN_ID, resp.openId); - - this.channel?.invokeMethod("onShareResponse", _result); - } - - onPayResp(resp: wechatSDK.PayResp) { - const _result: Map = new Map(); - _result.set(KEY_ERR_CODE, resp.errCode); - _result.set(KEY_ERR_STR, resp.errStr); - _result.set(KEY_TYPE, resp.type); - _result.set("prepayId", resp.prepayId); - _result.set("returnKey", resp.returnKey); - _result.set("extData", resp.extData); - - this.channel?.invokeMethod("onPayResponse", _result); - } - - onLaunchMiniProgramResp(resp: wechatSDK.LaunchMiniProgramResp) { - const _result: Map = new Map(); - _result.set(KEY_ERR_CODE, resp.errCode); - _result.set(KEY_ERR_STR, resp.errStr); - _result.set(KEY_TYPE, resp.type); - _result.set(KEY_OPEN_ID, resp.openId); - - if (resp.extMsg) { - _result.set("extMsg", resp.extMsg); - } - - this.channel?.invokeMethod("onLaunchMiniProgramResponse", _result); - } - - async handlePay(call: MethodCall, result: MethodResult) { - if (!WXAPiHandler.wxApi) { - result.error("Unassigned WxApi", "please config wxapi first", null); - return; - } - - const request = new wechatSDK.PayReq(); - request.appId = call.argument("appId"); - request.partnerId = call.argument("partnerId"); - request.prepayId = call.argument("prepayId"); - request.packageValue = call.argument("packageValue"); - request.nonceStr = call.argument("nonceStr"); - request.timeStamp = call.argument("timeStamp").toString(); - request.sign = call.argument("sign"); - request.signType = call.argument("signType"); - request.extData = call.argument("extData"); - - const done = await WXAPiHandler.wxApi?.sendReq(this.uiContext, request); - - result.success(done); - } - - attemptToResumeMsgFromWx(result: MethodResult) { - WXAPiHandler.wxApi?.handleWant(this.binding?.getAbility().launchWant, this) - } - - async launchMiniProgram(call: MethodCall, result: MethodResult) { - const request = new wechatSDK.LaunchMiniProgramReq(); - request.userName = call.argument("userName"); - request.path = call.argument("path"); - // sdk 内当前没 type 常量, 直接使用传入的参数 - request.miniprogramType = call.argument("miniProgramType") ?? 0; - - const done = await WXAPiHandler.wxApi?.sendReq(this.uiContext, request); - - result.success(done); - } - - async openBusinessView(call: MethodCall, result: MethodResult) { - const request = new wechatSDK.OpenBusinessViewReq(); - request.businessType = call.argument("businessType"); - request.query = call.argument("query"); - request.extInfo = `{"miniProgramType": 0}`; - - const done = await WXAPiHandler.wxApi?.sendReq(this.uiContext, request); - - result.success(done); - } - - async openWeChatCustomerServiceChat(call: MethodCall, result: MethodResult) { - const request = new wechatSDK.OpenCustomerServiceChatReq(); - request.corpId = call.argument("corpId") ?? ""; - request.url = call.argument("url") ?? ""; - - const done = await WXAPiHandler.wxApi?.sendReq(this.uiContext, request); - - result.success(done); - } -} diff --git a/ohos/src/main/ets/components/plugin/handlers/FluwxAuthHandler.ets b/ohos/src/main/ets/components/plugin/handlers/FluwxAuthHandler.ets deleted file mode 100644 index 64eb4b20..00000000 --- a/ohos/src/main/ets/components/plugin/handlers/FluwxAuthHandler.ets +++ /dev/null @@ -1,88 +0,0 @@ -import { MethodCall, MethodChannel, MethodResult } from "@ohos/flutter_ohos"; -import { DiffDevOAuthFactory, IDiffDevOAuth, OAuthCallback, OAuthErrCode, SendAuthReq } from "@tencent/wechat_open_sdk"; -import { WXAPiHandler } from "./WXAPiHandler"; -import { util } from "@kit.ArkTS"; - -export class FluwxAuthHandler implements OAuthCallback { - private channel: MethodChannel; - private diffDevOauth: IDiffDevOAuth | null = null; - - constructor(channel: MethodChannel) { - this.channel = channel; - } - - onGotQRCode = (base64JpegImageBuffer: string) => { - const base64Codec = new util.Base64Helper() - const bytes = base64Codec.decodeSync(base64JpegImageBuffer) - - this.channel.invokeMethod("onAuthGotQRCode", { - "errCode": 0, - "qrCode": bytes - }) - } - onQRCodeScanned = () => { - this.channel.invokeMethod("onQRCodeScanned", { - "errCode": 0 - }) - } - onAuthFinish = (authCode: string) => { - this.channel.invokeMethod("onAuthByQRCodeFinished", { - "authCode": authCode, - "errCode": 0 - }) - } - onAuthError = (errCode: OAuthErrCode, errMsg: string) => { - this.channel.invokeMethod("onAuthByQRCodeFinished", { - "errCode": errCode, - "errStr": errMsg - }) - } - - getDiffDevOauth(): IDiffDevOAuth { - if (this.diffDevOauth) { - this.diffDevOauth.stopOAuth(); - this.diffDevOauth = null; - } - this.diffDevOauth = DiffDevOAuthFactory.getDiffDevOAuth()!; - return this.diffDevOauth; - } - - async sendAuth(call: MethodCall, result: MethodResult) { - const req = new SendAuthReq(); - req.isOption1 = false; - req.scope = call.argument("scope"); - req.state = call.argument("state"); - const openid: string | null = call.argument("openid"); - if (openid) { - req.openId = openid; - } - req.nonAutomatic = call.argument("nonAutomatic") ?? false; - - const done = await WXAPiHandler.wxApi?.sendReq(WXAPiHandler.uiContext, req); - - result.success(done); - } - - authByQRCode(call: MethodCall, result: MethodResult) { - const appId: string = call.argument("appId") ?? ""; - const scope: string = call.argument("scope") ?? ""; - const nonceStr: string = call.argument("nonceStr") ?? ""; - const timeStamp: string = call.argument("timeStamp") ?? ""; - const signature: string = call.argument("signature") ?? ""; - - const qrCodeAuth = this.getDiffDevOauth(); - - result.success(qrCodeAuth.startOAuth( - appId, - scope, - nonceStr, - timeStamp, - signature, - this - )) - } - - stopAuthByQRCode(result: MethodResult) { - result.success(this.diffDevOauth?.stopOAuth()) - } -} \ No newline at end of file diff --git a/ohos/src/main/ets/components/plugin/handlers/FluwxShareHandler.ets b/ohos/src/main/ets/components/plugin/handlers/FluwxShareHandler.ets deleted file mode 100644 index 515b735f..00000000 --- a/ohos/src/main/ets/components/plugin/handlers/FluwxShareHandler.ets +++ /dev/null @@ -1,241 +0,0 @@ -import { Any, MethodCall, MethodResult } from "@ohos/flutter_ohos" -import { buffer } from "@kit.ArkTS" -import { fileUri, fileIo as fs } from "@kit.CoreFileKit" -import * as wxopensdk from '@tencent/wechat_open_sdk'; -import { WXAPiHandler } from "./WXAPiHandler" - -export class FluwxShareHandler { - share(call: MethodCall, result: MethodResult) { - if (!WXAPiHandler.wxApi) { - result.error("Unassigned WxApi", "please config wxapi first", null); - return; - } - - switch (call.method) { - case "shareText": - this.shareText(call, result); - break; - case "shareMiniProgram": - this.shareMiniProgram(call, result); - break; - case "shareImage": - this.shareImage(call, result); - break; - case "shareMusic": - // TODO - result.notImplemented(); - break; - case "shareVideo": - this.shareVideo(call, result); - break; - case "shareWebPage": - this.shareWebPage(call, result); - break; - case "shareFile": - this.shareFile(call, result); - break; - default: - result.notImplemented(); - break; - } - } - - async shareText(call: MethodCall, result: MethodResult) { - const textObj = new wxopensdk.WXTextObject(); - textObj.text = call.argument("source"); - - const mediaMsg = new wxopensdk.WXMediaMessage(); - mediaMsg.mediaObject = textObj; - - const req = new wxopensdk.SendMessageToWXReq(); - this.setCommonArgs(call, req, mediaMsg); - req.message = mediaMsg; - - const done = await WXAPiHandler.wxApi?.sendReq(WXAPiHandler.uiContext, req); - - result.success(done) - } - - async shareImage(call: MethodCall, result: MethodResult) { - const map: Map = call.argument("source") ?? new Map(); - // const imageHash: string | null = call.argument("imgDataHash"); - const bytes: Uint8Array | null = map.get("uint8List"); - - const imageObj = new wxopensdk.WXImageObject(); - - if (bytes) { - const buff: buffer.Buffer = buffer.from(bytes.buffer); - imageObj.imageData = buff.toString("base64", 0, buff.length); - } else { - const localImagePath: string | null = map.get("localImagePath"); - if (localImagePath) { - imageObj.uri = localImagePath.startsWith("file://") ? localImagePath : fileUri.getUriFromPath(localImagePath) - } - } - - const mediaMsg = new wxopensdk.WXMediaMessage(); - mediaMsg.mediaObject = imageObj; - - const req = new wxopensdk.SendMessageToWXReq(); - this.setCommonArgs(call, req, mediaMsg); - req.message = mediaMsg; - - const done = await WXAPiHandler.wxApi?.sendReq(WXAPiHandler.uiContext, req); - result.success(done); - } - - async shareWebPage(call: MethodCall, result: MethodResult) { - const webpageObject = new wxopensdk.WXWebpageObject() - webpageObject.webpageUrl = call.argument("webPage") - - const mediaMessage = new wxopensdk.WXMediaMessage() - mediaMessage.mediaObject = webpageObject - mediaMessage.title = call.argument("title") - mediaMessage.description = call.argument("description") - - const thumbData: Uint8Array | null = call.argument("thumbData"); - if (thumbData) { - mediaMessage.thumbData = thumbData; - } - - const req = new wxopensdk.SendMessageToWXReq() - this.setCommonArgs(call, req, mediaMessage) - req.message = mediaMessage - - const done = await WXAPiHandler.wxApi?.sendReq(WXAPiHandler.uiContext, req); - - result.success(done) - } - - async shareFile(call: MethodCall, result: MethodResult) { - const source: Map = call.argument("source") ?? new Map(); - const schemaIndex: number = source.get("schema") - let filePath: string = "" - - // check schema is file or binary - if (schemaIndex < 2) { - result.error("ARG", "currently only file or binary schema is supported on ohos", null); - return; - } - - // case schema is file - if(schemaIndex == 2) { - filePath = source.get("source") - if (filePath.startsWith("file://")) { - filePath = filePath; - } else { - filePath = fileUri.getUriFromPath(filePath); - } - } else { - // case schema is binary, write to temp file first - const bytes: Uint8Array = source.get("source"); - const suffix: string = source.get("suffix") ?? ".tmp"; - const fileName = `share_temp_${new Date().getTime()}${suffix}`; - const tempFilePath = `${WXAPiHandler.uiContext?.tempDir}/${fileName}`; - const tempFile = fs.openSync(tempFilePath, fs.OpenMode.READ_WRITE || fs.OpenMode.CREATE); - await fs.write(tempFile.fd, bytes.buffer); - await fs.close(tempFile.fd); - filePath = fileUri.getUriFromPath(tempFilePath); - } - - const fileObject = new wxopensdk.WXFileObject() - fileObject.fileUri = filePath - - const mediaMessage = new wxopensdk.WXMediaMessage() - mediaMessage.mediaObject = fileObject - mediaMessage.title = call.argument("title") || "" - mediaMessage.description = call.argument("description") || "" - - const req = new wxopensdk.SendMessageToWXReq() - this.setCommonArgs(call, req, mediaMessage) - req.message = mediaMessage - - const done = await WXAPiHandler.wxApi?.sendReq(WXAPiHandler.uiContext, req); - - result.success(done) - } - - async shareMiniProgram(call: MethodCall, result: MethodResult) { - const miniProgramObject = new wxopensdk.WXMiniProgramObject() - miniProgramObject.userName = call.argument("userName") - miniProgramObject.path = call.argument("path") - - let miniProgramType = wxopensdk.WXMiniProgramType.RELEASE - - let miniProgramTypeInt: number = call.argument("miniProgramType") - if (miniProgramTypeInt === 1) { - miniProgramType = wxopensdk.WXMiniProgramType.TEST - } else if (miniProgramTypeInt === 2) { - miniProgramType = wxopensdk.WXMiniProgramType.PREVIEW - } - - miniProgramObject.miniprogramType = miniProgramType - - const mediaMessage = new wxopensdk.WXMediaMessage() - mediaMessage.mediaObject = miniProgramObject - mediaMessage.title = call.argument("title") - mediaMessage.description = call.argument("description") - - const thumbData: Uint8Array | null = call.argument("thumbData"); - if (thumbData) { - mediaMessage.thumbData = thumbData; - } - - const req = new wxopensdk.SendMessageToWXReq() - this.setCommonArgs(call, req, mediaMessage) - req.message = mediaMessage - - const done = await WXAPiHandler.wxApi?.sendReq(WXAPiHandler.uiContext, req); - - result.success(done) - } - - async shareVideo(call: MethodCall, result: MethodResult) { - const videoObject = new wxopensdk.WXVideoObject() - const videoUrl: string | undefined = call.argument("videoUrl"); - const videoLowBandUrl: string | undefined = call.argument("videoLowBandUrl"); - - if (videoUrl) { - videoObject.videoUrl = videoUrl; - } else { - videoObject.videoLowBandUrl = videoLowBandUrl; - } - - const mediaMessage = new wxopensdk.WXMediaMessage() - mediaMessage.mediaObject = videoObject - mediaMessage.title = call.argument("title") || "" - mediaMessage.description = call.argument("description") || "" - - const req = new wxopensdk.SendMessageToWXReq() - this.setCommonArgs(call, req, mediaMessage) - req.message = mediaMessage - const done = await WXAPiHandler.wxApi?.sendReq(WXAPiHandler.uiContext, req); - result.success(done) - } - - setCommonArgs(call: MethodCall, req: wxopensdk.SendMessageToWXReq, msg: wxopensdk.WXMediaMessage) { - const thumbData: Uint8Array | undefined = call.argument("thumbData"); - const messageAction: string | undefined = call.argument("messageAction"); - - if (thumbData) { - msg.thumbData = thumbData; - } - - if (messageAction) { - msg.messageAction = messageAction; - } - - const sceneIndex: number = call.argument("scene") - switch (sceneIndex) { - case 0: - req.scene = wxopensdk.SendMessageToWXReq.WXSceneSession - break - case 1: - req.scene = wxopensdk.SendMessageToWXReq.WXSceneTimeline - break - default: - req.scene = wxopensdk.SendMessageToWXReq.WXSceneSession - break - } - } -} \ No newline at end of file diff --git a/ohos/src/main/ets/components/plugin/handlers/WXAPiHandler.ets b/ohos/src/main/ets/components/plugin/handlers/WXAPiHandler.ets deleted file mode 100644 index ce351205..00000000 --- a/ohos/src/main/ets/components/plugin/handlers/WXAPiHandler.ets +++ /dev/null @@ -1,65 +0,0 @@ -import * as wechatOpenSDK from "@tencent/wechat_open_sdk" -import { MethodCall, MethodResult } from '@ohos/flutter_ohos' -import { bundleManager, common } from '@kit.AbilityKit' - -export class WXAPiHandler { - static wxApi: wechatOpenSDK.WXApi | null = null - private static registered: boolean = false - private static context: common.UIAbilityContext | null = null - - static get wxApiRegistered() { - return WXAPiHandler.registered - } - static get uiContext() { - return WXAPiHandler.context - } - - static coolBoot: boolean = false - - static setContext(context: common.UIAbilityContext) { - WXAPiHandler.context = context - } - - static registerApp(call: MethodCall, result: MethodResult) { - if (WXAPiHandler.wxApi != null) { - result.success(true) - return - } - const appId: string | null = call.argument("appId") - if (!appId) { - result.error("invalid app id", "are you sure your app id is correct ?", appId) - return - } - - WXAPiHandler.registerWxAPIInternal(appId) - - result.success(WXAPiHandler.registered) - } - - static checkWeChatInstallation(result: MethodResult) { - const isInstalled = bundleManager.canOpenLink("weixin://") || WXAPiHandler.wxApi?.isWXAppInstalled() === true; - result.success(isInstalled); - } - - static checkSupportOpenBusinessView(result: MethodResult) { - if (!WXAPiHandler.wxApi) { - result.error("Unassigned WxApi", "please config wxapi first", null); - return; - } - - const isInstalled = bundleManager.canOpenLink("weixin://") || WXAPiHandler.wxApi?.isWXAppInstalled() === true; - if (!isInstalled) { - result.error("WeChat Not Installed", "Please install the WeChat first", null); - return; - } - - result.success(true); - } - - - private static registerWxAPIInternal(appId: string) { - let api = wechatOpenSDK.WXAPIFactory.createWXAPI(appId) - WXAPiHandler.registered = true - WXAPiHandler.wxApi = api - } -} \ No newline at end of file diff --git a/ohos/src/main/module.json5 b/ohos/src/main/module.json5 deleted file mode 100644 index d63604c0..00000000 --- a/ohos/src/main/module.json5 +++ /dev/null @@ -1,10 +0,0 @@ -{ - "module": { - "name": "fluwx", - "type": "har", - "deviceTypes": [ - "default", - "tablet" - ] - } -} diff --git a/packages/_shared/android/build.gradle.kts b/packages/_shared/android/build.gradle.kts index f013a026..555aada9 100644 --- a/packages/_shared/android/build.gradle.kts +++ b/packages/_shared/android/build.gradle.kts @@ -4,14 +4,14 @@ group = "com.jarvan.fluwx" version = "1.0-SNAPSHOT" buildscript { - val kotlinVersion = "2.2.20" + val kotlinVersion = "2.3.20" repositories { google() mavenCentral() } dependencies { - classpath("com.android.tools.build:gradle:8.11.1") + classpath("com.android.tools.build:gradle:9.0.1") classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion") classpath("org.yaml:snakeyaml:2.6") } @@ -26,9 +26,13 @@ allprojects { plugins { id("com.android.library") - id("kotlin-android") } +val agpMajor = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION.substringBefore('.').toInt() + +if (agpMajor < 9) { + apply(plugin = "org.jetbrains.kotlin.android") +} android { namespace = "com.jarvan.fluwx" @@ -39,10 +43,6 @@ android { targetCompatibility = JavaVersion.VERSION_17 } - kotlinOptions { - jvmTarget = JavaVersion.VERSION_17.toString() - } - sourceSets { getByName("main") { java.srcDirs("src/main/kotlin", "${layout.buildDirectory.get().asFile}/generated/src/kotlin") @@ -84,6 +84,19 @@ android { } } +kotlin { + compilerOptions { + jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17 + } +} + + +project.extensions.configure(org.jetbrains.kotlin.gradle.dsl.KotlinAndroidProjectExtension::class.java) { + compilerOptions { + jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17 + } +} + fun Project.loadPubspec(): Map { val yamlDir = if (rootProject.hasProperty("yamlDir")) rootProject.ext["yamlDir"] as String else "" val pubspecPath = "${rootProject.projectDir.parent}${File.separator}${yamlDir}pubspec.yaml" diff --git a/packages/fluwx/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/fluwx/example/android/gradle/wrapper/gradle-wrapper.properties index e4ef43fb..2d428bfb 100644 --- a/packages/fluwx/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/packages/fluwx/example/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-all.zip diff --git a/packages/fluwx/example/android/settings.gradle.kts b/packages/fluwx/example/android/settings.gradle.kts index ca7fe065..c21f0c5b 100644 --- a/packages/fluwx/example/android/settings.gradle.kts +++ b/packages/fluwx/example/android/settings.gradle.kts @@ -19,8 +19,8 @@ pluginManagement { plugins { id("dev.flutter.flutter-plugin-loader") version "1.0.0" - id("com.android.application") version "8.11.1" apply false - id("org.jetbrains.kotlin.android") version "2.2.20" apply false + id("com.android.application") version "9.0.1" apply false + id("org.jetbrains.kotlin.android") version "2.3.20" apply false } include(":app") diff --git a/packages/fluwx_no_pay/example/android/app/build.gradle.kts b/packages/fluwx_no_pay/example/android/app/build.gradle.kts index 31ac922e..18014ddb 100644 --- a/packages/fluwx_no_pay/example/android/app/build.gradle.kts +++ b/packages/fluwx_no_pay/example/android/app/build.gradle.kts @@ -1,6 +1,5 @@ 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") } @@ -15,10 +14,6 @@ android { targetCompatibility = JavaVersion.VERSION_17 } - kotlinOptions { - jvmTarget = JavaVersion.VERSION_17.toString() - } - defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId = "com.jarvan.fluwx_example" @@ -42,3 +37,9 @@ android { flutter { source = "../.." } + +kotlin { + compilerOptions { + jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17 + } +} diff --git a/packages/fluwx_no_pay/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/fluwx_no_pay/example/android/gradle/wrapper/gradle-wrapper.properties index e4ef43fb..2d428bfb 100644 --- a/packages/fluwx_no_pay/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/packages/fluwx_no_pay/example/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-all.zip diff --git a/packages/fluwx_no_pay/example/android/settings.gradle.kts b/packages/fluwx_no_pay/example/android/settings.gradle.kts index ca7fe065..c21f0c5b 100644 --- a/packages/fluwx_no_pay/example/android/settings.gradle.kts +++ b/packages/fluwx_no_pay/example/android/settings.gradle.kts @@ -19,8 +19,8 @@ pluginManagement { plugins { id("dev.flutter.flutter-plugin-loader") version "1.0.0" - id("com.android.application") version "8.11.1" apply false - id("org.jetbrains.kotlin.android") version "2.2.20" apply false + id("com.android.application") version "9.0.1" apply false + id("org.jetbrains.kotlin.android") version "2.3.20" apply false } include(":app") From f5260d27e9a92f50557b1f230691823a42cc0721 Mon Sep 17 00:00:00 2001 From: Jarvanmo Date: Thu, 21 May 2026 16:13:19 +0800 Subject: [PATCH 2/2] migrate to KGP --- packages/fluwx/example/android/app/build.gradle.kts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/fluwx/example/android/app/build.gradle.kts b/packages/fluwx/example/android/app/build.gradle.kts index 31ac922e..095c5bbf 100644 --- a/packages/fluwx/example/android/app/build.gradle.kts +++ b/packages/fluwx/example/android/app/build.gradle.kts @@ -1,6 +1,5 @@ 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") } @@ -15,10 +14,6 @@ android { targetCompatibility = JavaVersion.VERSION_17 } - kotlinOptions { - jvmTarget = JavaVersion.VERSION_17.toString() - } - defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId = "com.jarvan.fluwx_example" @@ -42,3 +37,10 @@ android { flutter { source = "../.." } + +kotlin { + compilerOptions { + jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17 + } +} +