diff --git a/.github/workflows/issue.yml b/.github/workflows/issue.yml new file mode 100644 index 0000000..8a4587e --- /dev/null +++ b/.github/workflows/issue.yml @@ -0,0 +1,13 @@ +name: Notify +on: + issues: + types: [opened] + issue_comment: + types: [created] +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Notify + run: curl --location --request POST 'https://api.finogeeks.club/api/v1/finstore/webhooks/61b331d79b3dad0001f72fa2/postreceive?nonce=jhd2QyrArsc' --header "Content-Type:application/json" --data-raw '{"msg":"仓库 ${{github.repository}} 有新的 issue"}' diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml new file mode 100644 index 0000000..b5872ff --- /dev/null +++ b/.github/workflows/pull_request.yml @@ -0,0 +1,11 @@ +name: Notify +on: + pull_request: + branches: [ master ] +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Notify + run: curl --location --request POST 'https://api.finogeeks.club/api/v1/finstore/webhooks/61b331d79b3dad0001f72fa2/postreceive?nonce=jhd2QyrArsc' --header "Content-Type:application/json" --data-raw '{"msg":"仓库 ${{github.repository}} 有新的 PR ${{ github.event.pull_request._links.html.href }}"}' diff --git a/.gitignore b/.gitignore index e78390d..5cedef4 100644 --- a/.gitignore +++ b/.gitignore @@ -5,13 +5,9 @@ .packages .pub/ -build/ -# See https://www.dartlang.org/guides/libraries/private-files - # Files and directories created by pub .dart_tool/ .packages -build/ # If you're building an application, you may want to check-in your pubspec.lock pubspec.lock @@ -27,3 +23,16 @@ doc/api/ *.js_ *.js.deps *.js.map + +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures + + +android/bin/ +android/.project diff --git a/README.md b/README.md index 33fb9e9..2aa614c 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,66 @@ -# 凡泰极客小程序 Flutter 插件 +

+ + + +

-本插件提供在 Flutter 运行环境中运行小程序能力。 +

+ FinClip Flutter SDK
+

+

+ 本项目提供在 Flutter 环境中运行小程序的能力 +

-## 集成 +

+ 👉 https://www.finclip.com/ 👈 +

-在项目pubspec.yaml文件中添加依赖 +
-``` + + + + + + + + + + +
+ +

+ +

+ +[官方网站](https://www.finclip.com/) | [示例小程序](https://www.finclip.com/#/market) | [开发文档](https://www.finclip.com/mop/document/) | [部署指南](https://www.finclip.com/mop/document/introduce/quickStart/cloud-server-deployment-guide.html) | [SDK 集成指南](https://www.finclip.com/mop/document/introduce/quickStart/intergration-guide.html) | [API 列表](https://www.finclip.com/mop/document/develop/api/overview.html) | [组件列表](https://www.finclip.com/mop/document/develop/component/overview.html) | [隐私承诺](https://www.finclip.com/mop/document/operate/safety.html) + +
+ +----- +## 🤔 FinClip 是什么? + +有没有**想过**,开发好的微信小程序能放在自己的 APP 里直接运行,只需要开发一次小程序,就能在不同的应用中打开它,是不是很不可思议? + +有没有**试过**,在自己的 APP 中引入一个 SDK ,应用中不仅可以打开小程序,还能自定义小程序接口,修改小程序样式,是不是觉得更不可思议? + +这就是 FinClip ,就是有这么多不可思议! + +## ⚠️ Flutter 使用注意 + +由于 FinClip 小程序技术主要通过 SDK 向 APP 提供运行小程序的能力,您看到的本仓库中长期未更新的文件并非“年久失修”,我们始终保持在 Flutter 环境中 SDK 资源的定期更新。如果您在集成使用过程中遇到任何问题,欢迎与我们联系。 + +## ⚙️ Flutter 集成 + +在项目 `pubspec.yaml` 文件中添加依赖 + +```yaml mop: latest.version ``` -## 示例 +## 🖥 示例 -``` +```flutter import 'package:flutter/material.dart'; import 'dart:async'; import 'dart:io'; @@ -34,7 +82,7 @@ class _MyAppState extends State { // Platform messages are asynchronous, so we initialize in an async method. Future init() async { - if (Platform.isIOS) { + if (Platform.isiOS) { //com.finogeeks.mopExample final res = await Mop.instance.initialize( '22LyZEib0gLTQdU3MUauARlLry7JL/2fRpscC9kpGZQA', '1c11d7252c53e0b6', @@ -115,15 +163,13 @@ class _MyAppState extends State { } ``` -## 接口文档 +## 📋 接口文档 -1. 初始化小程序 +### 1. 初始化小程序 -在使用sdk提供的api之前必须要初始化sdk,初始化sdk的接口为 + 在使用 SDK 提供的 API 之前必须要初始化 SDK ,初始化 SDK 的接口如下 ``` - - /// /// /// initialize mop miniprogram engine. /// 初始化小程序 @@ -137,18 +183,16 @@ class _MyAppState extends State { {String apiServer, String apiPrefix}) ``` -使用示例: - +使用示例: ``` final res = await Mop.instance.initialize( '22LyZEib0gLTQdU3MUauARlLry7JL/2fRpscC9kpGZQA', '1c11d7252c53e0b6', apiServer: 'https://api.finclip.com', apiPrefix: '/api/v1/mop'); ``` -2. 打开小程序 +### 2. 打开小程序 ``` - /// /// /// open the miniprogram [appId] from the mop server. /// 打开小程序 @@ -161,9 +205,9 @@ final res = await Mop.instance.initialize( {final String path, final String query, final int sequence}) ``` -3. 获取当前正在使用的小程序信息 +### 3. 获取当前正在使用的小程序信息 -当前小程序信息包括的字段有appId,name,icon,description,version,thumbnail +当前小程序信息包括的字段有 `appId`, `name`, `icon`, `description`, `version`, `thumbnail` ``` /// @@ -175,7 +219,7 @@ final res = await Mop.instance.initialize( Future> currentApplet() ``` -4. 关闭当前打开的所有小程序 +### 4. 关闭当前打开的所有小程序 ``` /// @@ -185,10 +229,9 @@ final res = await Mop.instance.initialize( Future closeAllApplets() ``` -5. 清除缓存的小程序 +### 5. 清除缓存的小程序 清除缓存的小程序,当再次打开时,会重新下载小程序 - ``` /// /// clear applets cache @@ -197,7 +240,7 @@ final res = await Mop.instance.initialize( Future clearApplets() ``` -6. 注册小程序事件处理 +### 6. 注册小程序事件处理 当小程序内触发指定事件时,会通知到使用者,比如小程序被转发,小程序需要获取用户信息,注册处理器来做出对应的响应 @@ -210,7 +253,6 @@ final res = await Mop.instance.initialize( ``` 处理器的结构 - ``` abstract class AppletHandler { /// @@ -238,19 +280,19 @@ abstract class AppletHandler { } ``` -7. 注册拓展api +### 7. 注册拓展 API -如果,我们的小程序SDK API不满足您的需求,您可以注册自定义的小程序API,然后就可以在小程序内调用自已定义的API了。 +如果,我们的小程序 SDK API 不满足您的需求,您可以注册自定义的小程序API,然后就可以在小程序内调用自已定义的 API 了。 -··· +``` /// /// register extension api /// 注册拓展api /// void registerExtensionApi(String name, ExtensionApiHandler handler) -··· +``` -ios需要在小程序根目录创建FinChatConf.js文件,配置实例如下 +iOS 需要在小程序根目录创建 `FinChatConf.js` 文件,配置实例如下 ``` module.exports = { @@ -263,4 +305,23 @@ module.exports = { } ] } -``` \ No newline at end of file +``` + +## 🔗 常用链接 +以下内容是您在 FinClip 进行开发与体验时,常见的问题与指引信息 + +- [FinClip 官网](https://www.finclip.com/#/home) +- [示例小程序](https://www.finclip.com/#/market) +- [文档中心](https://www.finclip.com/mop/document/) +- [SDK 部署指南](https://www.finclip.com/mop/document/introduce/quickStart/intergration-guide.html) +- [小程序代码结构](https://www.finclip.com/mop/document/develop/guide/structure.html) +- [iOS 集成指引](https://www.finclip.com/mop/document/runtime-sdk/ios/ios-integrate.html) +- [Android 集成指引](https://www.finclip.com/mop/document/runtime-sdk/android/android-integrate.html) +- [Flutter 集成指引](https://www.finclip.com/mop/document/runtime-sdk/flutter/flutter-integrate.html) + +## ☎️ 联系我们 +微信扫描下面二维码,关注官方公众号 **「凡泰极客」**,获取更多精彩内容。
+ + +微信扫描下面二维码,邀请进官方微信交流群(加好友备注:finclip 咨询),获取更多精彩内容。
+ diff --git a/android/.classpath b/android/.classpath new file mode 100644 index 0000000..4a04201 --- /dev/null +++ b/android/.classpath @@ -0,0 +1,6 @@ + + + + + + diff --git a/android/.settings/org.eclipse.buildship.core.prefs b/android/.settings/org.eclipse.buildship.core.prefs new file mode 100644 index 0000000..1755e36 --- /dev/null +++ b/android/.settings/org.eclipse.buildship.core.prefs @@ -0,0 +1,13 @@ +arguments= +auto.sync=false +build.scans.enabled=false +connection.gradle.distribution=GRADLE_DISTRIBUTION(VERSION(7.0-rc-1)) +connection.project.dir= +eclipse.preferences.version=1 +gradle.user.home= +java.home=C\:/Program Files/Eclipse Foundation/jdk-11.0.12.7-hotspot +jvm.arguments= +offline.mode=false +override.workspace.settings=true +show.console.view=true +show.executions.view=true diff --git a/android/build.gradle b/android/build.gradle index 8fd14ed..30d5449 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -31,7 +31,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:3.5.3' + classpath 'com.android.tools.build:gradle:4.1.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.61" } @@ -68,6 +68,7 @@ android { minSdkVersion 21 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } + buildTypes { release { minifyEnabled false @@ -91,6 +92,6 @@ kapt { } dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') - implementation 'com.finogeeks.lib:finapplet:2.35.0-alpha20211231v09' - implementation 'com.finogeeks.mop:plugins:2.35.0-alpha20211231v09' + implementation 'com.finogeeks.lib:finapplet:2.35.1' + implementation 'com.finogeeks.mop:plugins:2.35.1' } \ No newline at end of file diff --git a/android/build.gradle.tpl b/android/build.gradle.tpl deleted file mode 100644 index 3334d92..0000000 --- a/android/build.gradle.tpl +++ /dev/null @@ -1,96 +0,0 @@ - -apply plugin: 'com.android.library' - -apply plugin: 'kotlin-android' -apply plugin: 'kotlin-kapt' -apply plugin: 'kotlin-android-extensions' - -group 'com.finogeeks.mop' -version '1.0' - -buildscript { - repositories { - google() - jcenter() - maven { - url "https://gradle.finogeeks.club/repository/finogeeks/" - credentials { - username "finclip" - password "Abcd@@1234" - } - } - maven { - url "https://gradle.finogeeks.club/repository/applet/" - credentials { - username "finclip" - password "Abcd@@1234" - } - } - maven { url "https://jitpack.io" } - - } - - dependencies { - classpath 'com.android.tools.build:gradle:3.5.3' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.61" - - } -} - -rootProject.allprojects { - repositories { - google() - jcenter() - maven { - url "https://gradle.finogeeks.club/repository/finogeeks/" - credentials { - username "finclip" - password "Abcd@@1234" - } - } - maven { - url "https://gradle.finogeeks.club/repository/applet/" - credentials { - username "finclip" - password "Abcd@@1234" - } - } - maven { url "https://jitpack.io" } - - } -} - - -android { - compileSdkVersion 28 - - defaultConfig { - minSdkVersion 21 - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - } - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' - } - } - - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - lintOptions { - disable 'InvalidPackage' - } -} - -kapt { - arguments { - arg("moduleName", project.getName()) - } -} -dependencies { - implementation fileTree(include: ['*.jar'], dir: 'libs') - implementation 'com.finogeeks.lib:finapplet:__finapplet_version__' - implementation 'com.finogeeks.mop:plugins:__finapplet_version__' -} \ No newline at end of file diff --git a/android/gradle.properties b/android/gradle.properties index 1441b1d..94adc3a 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,3 +1,3 @@ org.gradle.jvmargs=-Xmx1536M - -android.enableR8=true +android.useAndroidX=true +android.enableJetifier=true diff --git a/android/gradle/wrapper/gradle-wrapper.jar b/android/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 13372ae..0000000 Binary files a/android/gradle/wrapper/gradle-wrapper.jar and /dev/null differ diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index d757f3d..3c9d085 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/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-5.4.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip diff --git a/android/gradlew b/android/gradlew deleted file mode 100755 index 9d82f78..0000000 --- a/android/gradlew +++ /dev/null @@ -1,160 +0,0 @@ -#!/usr/bin/env bash - -############################################################################## -## -## Gradle start up script for UN*X -## -############################################################################## - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn ( ) { - echo "$*" -} - -die ( ) { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; -esac - -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=$((i+1)) - done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") -} -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" - -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/android/gradlew.bat b/android/gradlew.bat deleted file mode 100644 index aec9973..0000000 --- a/android/gradlew.bat +++ /dev/null @@ -1,90 +0,0 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windowz variants - -if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/android/src/main/java/com/finogeeks/mop/MopEventStream.java b/android/src/main/java/com/finogeeks/mop/MopEventStream.java index baed58d..42c9a29 100644 --- a/android/src/main/java/com/finogeeks/mop/MopEventStream.java +++ b/android/src/main/java/com/finogeeks/mop/MopEventStream.java @@ -5,9 +5,9 @@ import java.util.Map; import io.flutter.plugin.common.EventChannel; - -public class MopEventStream implements EventChannel.StreamHandler { +public class MopEventStream implements EventChannel.StreamHandler { EventChannel.EventSink mEventSlink; + @Override public void onListen(Object o, EventChannel.EventSink eventSink) { mEventSlink = eventSink; @@ -17,12 +17,13 @@ public class MopEventStream implements EventChannel.StreamHandler { public void onCancel(Object o) { mEventSlink = null; } - public void send(String channel,String event,Object body) { + + public void send(String channel, String event, Object body) { if (mEventSlink != null) { - Map map = new HashMap<>(); - map.put("channel",channel); - map.put("event",event); - map.put("body",body); + Map map = new HashMap<>(); + map.put("channel", channel); + map.put("event", event); + map.put("body", body); mEventSlink.success(map); } } diff --git a/android/src/main/java/com/finogeeks/mop/MopPlugin.java b/android/src/main/java/com/finogeeks/mop/MopPlugin.java index 0740f8c..75a9ce4 100644 --- a/android/src/main/java/com/finogeeks/mop/MopPlugin.java +++ b/android/src/main/java/com/finogeeks/mop/MopPlugin.java @@ -1,7 +1,9 @@ package com.finogeeks.mop; +import android.app.Activity; import android.content.Intent; import android.util.Log; +import androidx.lifecycle.Lifecycle; import com.finogeeks.mop.interfaces.Event; import com.finogeeks.mop.interfaces.FlutterInterface; @@ -11,6 +13,10 @@ import com.finogeeks.mop.service.MopPluginService; import java.util.HashMap; import java.util.Map; +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.embedding.engine.plugins.lifecycle.FlutterLifecycleAdapter; import io.flutter.plugin.common.EventChannel; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; @@ -22,78 +28,125 @@ import io.flutter.plugin.common.PluginRegistry.Registrar; /** * MopPlugin */ -public class MopPlugin implements MethodCallHandler { - private static final String LOG_TAG = MopPlugin.class.getSimpleName(); +public class MopPlugin implements FlutterPlugin, MethodCallHandler, ActivityAware { + private static final String LOG_TAG = MopPlugin.class.getSimpleName(); - private static final String CHANNEL = "mop"; - private PluginRegistry.Registrar registrar; - private FlutterInterface flutterInterface; - private MopPluginDelegate delegate; + private static final String CHANNEL = "mop"; + private static final String EVENT_CHANNEL = "plugins.mop.finogeeks.com/mop_event"; + private final FlutterInterface flutterInterface = new FlutterInterface(); + private final MopPluginDelegate delegate = new MopPluginDelegate(); + private final MopEventStream mopEventStream = new MopEventStream(); - /** - * Plugin registration. - */ - public static void registerWith(Registrar registrar) { - final MethodChannel channel = new MethodChannel(registrar.messenger(), CHANNEL); - final MopPluginDelegate delegate = new MopPluginDelegate(registrar.activity()); - final MopPlugin instance = new MopPlugin(registrar, delegate); - channel.setMethodCallHandler(instance); - final EventChannel eventChannel = new EventChannel(registrar.messenger(), "plugins.mop.finogeeks.com/mop_event"); - MopEventStream mopEventStream = new MopEventStream(); - eventChannel.setStreamHandler(mopEventStream); - MopPluginService.getInstance().initialize(registrar.activity(), mopEventStream, channel); + // These are null when not using v2 embedding. + private FlutterPluginBinding flutterPluginBinding; + private MethodChannel channel; + private EventChannel eventChannel; + private Lifecycle lifecycle; - } + /** + * Plugin registration. + */ + @SuppressWarnings("deprecation") + public static void registerWith(Registrar registrar) { + MethodChannel channel = new MethodChannel(registrar.messenger(), CHANNEL); + MopPluginDelegate delegate = new MopPluginDelegate(); + final MopPlugin plugin = new MopPlugin(); + channel.setMethodCallHandler(plugin); + registrar.addActivityResultListener(delegate); - MopPlugin(PluginRegistry.Registrar registrar, MopPluginDelegate delegate) { - this.registrar = registrar; - this.flutterInterface = new FlutterInterface(); - this.delegate = delegate; - } + EventChannel eventChannel = new EventChannel(registrar.messenger(), EVENT_CHANNEL); + final MopEventStream mopEventStream = new MopEventStream(); + eventChannel.setStreamHandler(mopEventStream); + MopPluginService.getInstance().initialize(registrar.activity(), mopEventStream, channel); + } - @Override - public void onMethodCall(MethodCall call, final Result result) { - registrar.addActivityResultListener(delegate); - ICallback callback = new ICallback() { - @Override - public void onSuccess(Object data) { - Map obj = new HashMap(); + @Override + public void onMethodCall(MethodCall call, final Result result) { + ICallback callback = new ICallback() { + @Override + public void onSuccess(Object data) { + Map obj = new HashMap(); - obj.put("success", true); - if (data != null) - obj.put("data", data); - obj.put("retMsg", "ok"); - result.success(obj); - } + obj.put("success", true); + if (data != null) + obj.put("data", data); + obj.put("retMsg", "ok"); + result.success(obj); + } - @Override - public void onFail(Object error) { - Map obj = new HashMap(); - obj.put("success", false); - obj.put("retMsg", error == null ? "" : error); - result.success(obj); - } + @Override + public void onFail(Object error) { + Map obj = new HashMap(); + obj.put("success", false); + obj.put("retMsg", error == null ? "" : error); + result.success(obj); + } - @Override - public void onCancel(Object cancel) { - result.notImplemented(); - } + @Override + public void onCancel(Object cancel) { + result.notImplemented(); + } - @Override - public void startActivityForResult(Intent intent, int requestCode) { + @Override + public void startActivityForResult(Intent intent, int requestCode) { - } - }; - Log.d(LOG_TAG, "mopplugin: invoke " + call.method); - Event event = new Event(call.method, call.arguments, callback); - delegate.setEvent(event); - this.flutterInterface.invokeHandler(event); -// if (call.method.equals("getPlatformVersion")) { -// result.success("Android " + android.os.Build.VERSION.RELEASE); -// } else { -// result.notImplemented(); -// } - } + } + }; + Log.d(LOG_TAG, "mopplugin: invoke " + call.method); + Event event = new Event(call.method, call.arguments, callback); + delegate.setEvent(event); + this.flutterInterface.invokeHandler(event); + // if (call.method.equals("getPlatformVersion")) { + // result.success("Android " + android.os.Build.VERSION.RELEASE); + // } else { + // result.notImplemented(); + // } + } + @Override + public void onAttachedToEngine(FlutterPluginBinding binding) { + this.flutterPluginBinding = binding; + channel = new MethodChannel(binding.getFlutterEngine().getDartExecutor(), CHANNEL); + channel.setMethodCallHandler(this); + EventChannel eventChannel = new EventChannel(binding.getFlutterEngine().getDartExecutor(), EVENT_CHANNEL); + eventChannel.setStreamHandler(mopEventStream); + } + + @Override + public void onDetachedFromEngine(FlutterPluginBinding binding) { + this.flutterPluginBinding = null; + } + + @Override + public void onAttachedToActivity(ActivityPluginBinding binding) { + binding.addActivityResultListener(delegate); + lifecycle = FlutterLifecycleAdapter.getActivityLifecycle(binding); + setServicesFromActivity(binding.getActivity()); + channel.setMethodCallHandler(this); + } + + @Override + public void onDetachedFromActivityForConfigChanges() { + lifecycle = null; + } + + @Override + public void onReattachedToActivityForConfigChanges(ActivityPluginBinding binding) { + binding.addActivityResultListener(delegate); + lifecycle = FlutterLifecycleAdapter.getActivityLifecycle(binding); + setServicesFromActivity(binding.getActivity()); + } + + @Override + public void onDetachedFromActivity() { + lifecycle = null; + channel.setMethodCallHandler(null); + } + + private void setServicesFromActivity(Activity activity) { + if (activity == null) + return; + MopPluginService.getInstance().initialize(activity, mopEventStream, channel); + } } diff --git a/android/src/main/java/com/finogeeks/mop/MopPluginDelegate.java b/android/src/main/java/com/finogeeks/mop/MopPluginDelegate.java index 23ec9a3..e953059 100644 --- a/android/src/main/java/com/finogeeks/mop/MopPluginDelegate.java +++ b/android/src/main/java/com/finogeeks/mop/MopPluginDelegate.java @@ -9,11 +9,8 @@ import com.finogeeks.mop.service.MopPluginService; import io.flutter.plugin.common.PluginRegistry; - public class MopPluginDelegate implements PluginRegistry.ActivityResultListener { - private Event mEvent; - private final Activity activity; public Event getEvent() { return mEvent; @@ -23,16 +20,11 @@ public class MopPluginDelegate implements PluginRegistry.ActivityResultListener this.mEvent = event; } - public MopPluginDelegate(final Activity activity) { - this.activity = activity; - - } @Override public boolean onActivityResult(int requestCode, int resultCode, Intent data) { - if (requestCode == Constants.REQUEST_CODE_CHOOSE - || requestCode == Constants.REQUEST_CODE_LOCATION_CHOOSE - ) { - MopPluginService.getInstance().getApisManager().getApiInstance(mEvent).onActivityResult(requestCode, resultCode, data, mEvent.getCallback()); + if (requestCode == Constants.REQUEST_CODE_CHOOSE || requestCode == Constants.REQUEST_CODE_LOCATION_CHOOSE) { + MopPluginService.getInstance().getApisManager().getApiInstance(mEvent).onActivityResult(requestCode, + resultCode, data, mEvent.getCallback()); } return true; } diff --git a/android/src/main/java/com/finogeeks/mop/api/mop/AppletManageModule.java b/android/src/main/java/com/finogeeks/mop/api/mop/AppletManageModule.java index 216c4ae..4593530 100644 --- a/android/src/main/java/com/finogeeks/mop/api/mop/AppletManageModule.java +++ b/android/src/main/java/com/finogeeks/mop/api/mop/AppletManageModule.java @@ -1,11 +1,20 @@ package com.finogeeks.mop.api.mop; import android.content.Context; +import android.util.Log; +import com.finogeeks.lib.applet.anim.FadeInAnim; +import com.finogeeks.lib.applet.anim.NoneAnim; +import com.finogeeks.lib.applet.anim.SlideFromBottomToTopAnim; +import com.finogeeks.lib.applet.anim.SlideFromLeftToRightAnim; +import com.finogeeks.lib.applet.anim.SlideFromRightToLeftAnim; +import com.finogeeks.lib.applet.anim.SlideFromTopToBottomAnim; import com.finogeeks.lib.applet.client.FinAppClient; import com.finogeeks.lib.applet.db.entity.FinApplet; +import com.finogeeks.lib.applet.interfaces.FinCallback; import com.finogeeks.mop.api.BaseApi; import com.finogeeks.mop.interfaces.ICallback; +import com.google.gson.Gson; import java.util.HashMap; import java.util.Map; @@ -13,13 +22,16 @@ import java.util.Map; public class AppletManageModule extends BaseApi { + private static final String TAG = "AppletManageModule"; + public AppletManageModule(Context context) { super(context); } @Override public String[] apis() { - return new String[]{"currentApplet", "closeAllApplets", "clearApplets", "removeUsedApplet"}; + return new String[]{"currentApplet", "closeAllApplets", "clearApplets", "removeUsedApplet", + "setActivityTransitionAnim", "sendCustomEvent", "callJS"}; } @Override @@ -57,6 +69,70 @@ public class AppletManageModule extends BaseApi { } else { callback.onFail(null); } + } else if (event.equals("setActivityTransitionAnim")) { + String anim = (String) param.get("anim"); + Log.d(TAG, "setActivityTransitionAnim:" + anim); + if ("SlideFromLeftToRightAnim".equals(anim)) { + FinAppClient.INSTANCE.getAppletApiManager().setActivityTransitionAnim(SlideFromLeftToRightAnim.INSTANCE); + } else if ("SlideFromRightToLeftAnim".equals(anim)) { + FinAppClient.INSTANCE.getAppletApiManager().setActivityTransitionAnim(SlideFromRightToLeftAnim.INSTANCE); + } else if ("SlideFromTopToBottomAnim".equals(anim)) { + FinAppClient.INSTANCE.getAppletApiManager().setActivityTransitionAnim(SlideFromTopToBottomAnim.INSTANCE); + } else if ("SlideFromBottomToTopAnim".equals(anim)) { + FinAppClient.INSTANCE.getAppletApiManager().setActivityTransitionAnim(SlideFromBottomToTopAnim.INSTANCE); + } else if ("FadeInAnim".equals(anim)) { + FinAppClient.INSTANCE.getAppletApiManager().setActivityTransitionAnim(FadeInAnim.INSTANCE); + } else if ("NoneAnim".equals(anim)) { + FinAppClient.INSTANCE.getAppletApiManager().setActivityTransitionAnim(NoneAnim.INSTANCE); + } + callback.onSuccess(null); + } else if (event.equals("sendCustomEvent")) { + String appId = (String) param.get("appId"); + Map eventData = (Map) param.get("eventData"); + Log.d(TAG, "sendCustomEvent:" + appId); + if (appId != null) { + FinAppClient.INSTANCE.getAppletApiManager().sendCustomEvent(appId, eventData == null ? "" : new Gson().toJson(eventData)); + callback.onSuccess(null); + } else { + callback.onFail(null); + } + } else if (event.equals("callJS")) { + String appId = (String) param.get("appId"); + String eventName = (String) param.get("eventName"); + String nativeViewId = (String) param.get("nativeViewId"); + int viewId = 0; + if (nativeViewId != null && !nativeViewId.equals("")) { + try { + viewId = Integer.parseInt(nativeViewId); + } catch (Exception e) { + e.printStackTrace(); + } + } + Map eventData = (Map) param.get("eventData"); + Log.d(TAG, "callJS:" + appId); + if (appId != null && eventName != null) { + FinAppClient.INSTANCE.getAppletApiManager().callJS(appId, eventName, eventData == null ? "" : new Gson().toJson(eventData), + viewId, new FinCallback() { + @Override + public void onSuccess(String s) { + Map res = new HashMap<>(); + res.put("data", s); + callback.onSuccess(res); + } + + @Override + public void onError(int i, String s) { + callback.onFail(null); + } + + @Override + public void onProgress(int i, String s) { + + } + }); + } else { + callback.onFail(null); + } } } } diff --git a/android/src/main/java/com/finogeeks/mop/api/mop/AppletModule.java b/android/src/main/java/com/finogeeks/mop/api/mop/AppletModule.java index 8345e46..cfab8ad 100644 --- a/android/src/main/java/com/finogeeks/mop/api/mop/AppletModule.java +++ b/android/src/main/java/com/finogeeks/mop/api/mop/AppletModule.java @@ -6,6 +6,7 @@ import android.util.Log; import com.finogeeks.lib.applet.client.FinAppClient; import com.finogeeks.lib.applet.interfaces.FinCallback; +import com.finogeeks.lib.applet.client.FinAppInfo; import com.finogeeks.lib.applet.sdk.model.StartAppletDecryptRequest; import com.finogeeks.mop.api.BaseApi; import com.finogeeks.mop.interfaces.ICallback; @@ -56,19 +57,20 @@ public class AppletModule extends BaseApi { String appId = String.valueOf(param.get("appId")); Integer sequence = (Integer) param.get("sequence"); Map params = (Map) param.get("params"); + String apiServer = (String) param.get("apiServer"); // mContext是FlutterActivity, // 在Android 6.0、7.0系统的部分设备中热启动小程序时,如果context参数用mContext,会出现无法启动小程序的问题 // 所以这里使用Application Context Context context = mContext.getApplicationContext(); - if (params == null) { - if (sequence == null) { - FinAppClient.INSTANCE.getAppletApiManager().startApplet(context, appId); - } else { - FinAppClient.INSTANCE.getAppletApiManager().startApplet(context, appId, sequence, null); - } + FinAppInfo.StartParams startParams = params == null ? null : new FinAppInfo.StartParams(params.get("path"), params.get("query"), params.get("scene")); + Log.d(TAG, "openApplet:" + appId + "," + param + "," + sequence + "," + apiServer); + + if (apiServer != null) { + FinAppClient.INSTANCE.getAppletApiManager().startApplet(context, apiServer, appId, sequence, startParams); } else { - FinAppClient.INSTANCE.getAppletApiManager().startApplet(context, appId, params); + FinAppClient.INSTANCE.getAppletApiManager().startApplet(context, appId, sequence, startParams); } + // String apiServer = (String) param.get("apiServer"); // String apiPrefix = (String) param.get("apiPrefix"); // if (apiServer == null || apiServer.isEmpty() || apiPrefix == null || apiPrefix.isEmpty()) { diff --git a/android/src/main/java/com/finogeeks/mop/api/mop/BaseModule.java b/android/src/main/java/com/finogeeks/mop/api/mop/BaseModule.java index f892b22..1db0bb0 100644 --- a/android/src/main/java/com/finogeeks/mop/api/mop/BaseModule.java +++ b/android/src/main/java/com/finogeeks/mop/api/mop/BaseModule.java @@ -2,6 +2,7 @@ package com.finogeeks.mop.api.mop; import android.app.Application; import android.content.Context; +import android.util.Log; import com.finogeeks.lib.applet.BuildConfig; import com.finogeeks.lib.applet.client.FinAppClient; @@ -11,6 +12,8 @@ import com.finogeeks.lib.applet.interfaces.FinCallback; import com.finogeeks.mop.api.BaseApi; import com.finogeeks.mop.interfaces.ICallback; import com.finogeeks.mop.service.MopPluginService; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; import java.util.ArrayList; import java.util.List; @@ -74,7 +77,22 @@ public class BaseModule extends BaseApi { Boolean bindAppletWithMainProcess = (Boolean) param.get("bindAppletWithMainProcess"); if (bindAppletWithMainProcess == null) bindAppletWithMainProcess = false; - FinAppConfig config = new FinAppConfig.Builder() + String customWebViewUserAgent = (String) param.get("customWebViewUserAgent"); + Integer appletIntervalUpdateLimit = (Integer) param.get("appletIntervalUpdateLimit"); + Integer maxRunningApplet = (Integer) param.get("maxRunningApplet"); + Gson gson = new Gson(); + List finStoreConfigs = null; + if (param.get("finStoreConfigs") != null) { + finStoreConfigs = gson.fromJson(gson.toJson(param.get("finStoreConfigs")), new TypeToken>() { + }.getType()); + } + FinAppConfig.UIConfig uiConfig = null; + if (param.get("uiConfig") != null) { + uiConfig = gson.fromJson(gson.toJson(param.get("uiConfig")), FinAppConfig.UIConfig.class); + } + + + FinAppConfig.Builder builder = new FinAppConfig.Builder() .setSdkKey(appkey) .setSdkSecret(secret) .setApiUrl(apiServer) @@ -84,8 +102,18 @@ public class BaseModule extends BaseApi { .setUserId(userId) .setDebugMode(debug) .setDisableRequestPermissions(disablePermission) - .setBindAppletWithMainProcess(bindAppletWithMainProcess) - .build(); + .setBindAppletWithMainProcess(bindAppletWithMainProcess); + + if (customWebViewUserAgent != null) + builder.setCustomWebViewUserAgent(customWebViewUserAgent); + if (appletIntervalUpdateLimit != null) + builder.setAppletIntervalUpdateLimit(appletIntervalUpdateLimit); + if (maxRunningApplet != null) builder.setMaxRunningApplet(maxRunningApplet); + if (finStoreConfigs != null) builder.setFinStoreConfigs(finStoreConfigs); + if (uiConfig != null) builder.setUiConfig(uiConfig); + + FinAppConfig config = builder.build(); + Log.d(TAG, "config:" + gson.toJson(config)); final Application application = MopPluginService.getInstance().getActivity().getApplication(); // SDK初始化结果回调,用于接收SDK初始化状态 diff --git a/android/src/main/java/com/finogeeks/mop/api/mop/ExtensionApiModule.java b/android/src/main/java/com/finogeeks/mop/api/mop/ExtensionApiModule.java index b6cc51f..3e07c59 100644 --- a/android/src/main/java/com/finogeeks/mop/api/mop/ExtensionApiModule.java +++ b/android/src/main/java/com/finogeeks/mop/api/mop/ExtensionApiModule.java @@ -33,66 +33,126 @@ public class ExtensionApiModule extends BaseApi { @Override public String[] apis() { - return new String[]{"registerExtensionApi"}; + return new String[]{"registerExtensionApi","addWebExtentionApi"}; } @Override public void invoke(String s, Map param, ICallback iCallback) { - MethodChannel channel = MopPluginService.getInstance().getMethodChannel(); - String name = (String) param.get("name"); - FinAppClient.INSTANCE.getExtensionApiManager().registerApi(new com.finogeeks.lib.applet.api.BaseApi(getContext()) { - @Override - public String[] apis() { - return new String[]{name}; - } + if(s.equals("registerExtensionApi")) { + MethodChannel channel = MopPluginService.getInstance().getMethodChannel(); + String name = (String) param.get("name"); + Log.d(TAG, "registerExtensionApi:" + name); + FinAppClient.INSTANCE.getExtensionApiManager().registerApi(new com.finogeeks.lib.applet.api.BaseApi(getContext()) { + @Override + public String[] apis() { + return new String[]{name}; + } - @Override - public void invoke(String s, JSONObject jsonObject, com.finogeeks.lib.applet.interfaces.ICallback iCallback) { - Log.d("MopPlugin", "invoke extensionApi:" + s + ",params:" + jsonObject); - Map params = GsonUtil.gson.fromJson(jsonObject.toString(), HashMap.class); - handler.post(() -> { - channel.invokeMethod("extensionApi:" + name, params, new MethodChannel.Result() { - @Override - public void success(Object result) { - String json = GsonUtil.gson.toJson(result); - FinAppTrace.d(ExtensionApiModule.TAG, "channel invokeMethod:" + name - + " success, result=" + result + ", json=" + json); - JSONObject ret = null; - if (json != null && !json.equals("null")) { - try { - ret = new JSONObject(json); - if (ret.has("errMsg")) { - String errMsg = ret.getString("errMsg"); - if (errMsg.startsWith(name + ":fail")) { - iCallback.onFail(ret); - return; + @Override + public void invoke(String s, JSONObject jsonObject, com.finogeeks.lib.applet.interfaces.ICallback iCallback) { + Log.d("MopPlugin", "invoke extensionApi:" + s + ",params:" + jsonObject); + Map params = GsonUtil.gson.fromJson(jsonObject.toString(), HashMap.class); + handler.post(() -> { + channel.invokeMethod("extensionApi:" + name, params, new MethodChannel.Result() { + @Override + public void success(Object result) { + String json = GsonUtil.gson.toJson(result); + FinAppTrace.d(ExtensionApiModule.TAG, "channel invokeMethod:" + name + + " success, result=" + result + ", json=" + json); + JSONObject ret = null; + if (json != null && !json.equals("null")) { + try { + ret = new JSONObject(json); + if (ret.has("errMsg")) { + String errMsg = ret.getString("errMsg"); + if (errMsg.startsWith(name + ":fail")) { + iCallback.onFail(ret); + return; + } } + } catch (JSONException e) { + e.printStackTrace(); } - } catch (JSONException e) { - e.printStackTrace(); } + + iCallback.onSuccess(ret); } - iCallback.onSuccess(ret); - } + @Override + public void error(String errorCode, String errorMessage, Object errorDetails) { + FinAppTrace.e(ExtensionApiModule.TAG, "channel invokeMethod:" + name + + " error, errorCode=" + errorCode + + ", errorMessage=" + errorMessage + + ", errorDetails=" + errorDetails); + iCallback.onFail(); + } - @Override - public void error(String errorCode, String errorMessage, Object errorDetails) { - FinAppTrace.e(ExtensionApiModule.TAG, "channel invokeMethod:" + name - + " error, errorCode=" + errorCode - + ", errorMessage=" + errorMessage - + ", errorDetails=" + errorDetails); - iCallback.onFail(); - } - - @Override - public void notImplemented() { - iCallback.onFail(); - } + @Override + public void notImplemented() { + iCallback.onFail(); + } + }); }); - }); - } - }); + } + }); + }else if(s.equals("addWebExtentionApi")){ + MethodChannel channel = MopPluginService.getInstance().getMethodChannel(); + String name = (String) param.get("name"); + Log.d(TAG, "addWebExtentionApi:" + name); + FinAppClient.INSTANCE.getExtensionWebApiManager().registerApi(new com.finogeeks.lib.applet.api.BaseApi(getContext()) { + @Override + public String[] apis() { + return new String[]{name}; + } + + @Override + public void invoke(String s, JSONObject jsonObject, com.finogeeks.lib.applet.interfaces.ICallback iCallback) { + Log.d("MopPlugin", "invoke webextensionApi:" + s + ",params:" + jsonObject); + Map params = GsonUtil.gson.fromJson(jsonObject.toString(), HashMap.class); + handler.post(() -> { + channel.invokeMethod("webExtentionApi:" + name, params, new MethodChannel.Result() { + @Override + public void success(Object result) { + String json = GsonUtil.gson.toJson(result); + FinAppTrace.d(ExtensionApiModule.TAG, "channel invokeMethod:" + name + + " success, result=" + result + ", json=" + json); + JSONObject ret = null; + if (json != null && !json.equals("null")) { + try { + ret = new JSONObject(json); + if (ret.has("errMsg")) { + String errMsg = ret.getString("errMsg"); + if (errMsg.startsWith(name + ":fail")) { + iCallback.onFail(ret); + return; + } + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + + iCallback.onSuccess(ret); + } + + @Override + public void error(String errorCode, String errorMessage, Object errorDetails) { + FinAppTrace.e(ExtensionApiModule.TAG, "channel invokeMethod:" + name + + " error, errorCode=" + errorCode + + ", errorMessage=" + errorMessage + + ", errorDetails=" + errorDetails); + iCallback.onFail(); + } + + @Override + public void notImplemented() { + iCallback.onFail(); + } + }); + }); + } + }); + } } } diff --git a/example/.flutter-plugins-dependencies b/example/.flutter-plugins-dependencies index 64b440d..fe53f56 100644 --- a/example/.flutter-plugins-dependencies +++ b/example/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"mop","path":"/Users/beetle/Desktop/finogeeks/gitlab/finosprite/finclip-flutter-sdk/","dependencies":[]}],"android":[{"name":"mop","path":"/Users/beetle/Desktop/finogeeks/gitlab/finosprite/finclip-flutter-sdk/","dependencies":[]}],"macos":[],"linux":[],"windows":[],"web":[]},"dependencyGraph":[{"name":"mop","dependencies":[]}],"date_created":"2021-12-30 16:09:08.189707","version":"2.2.2"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"mop","path":"/Users/kangxuyao/StudioProjects/finclip-flutter-sdk/","dependencies":[]}],"android":[{"name":"flutter_plugin_android_lifecycle","path":"/Users/kangxuyao/.pub-cache/hosted/pub.flutter-io.cn/flutter_plugin_android_lifecycle-2.0.5/","dependencies":[]},{"name":"mop","path":"/Users/kangxuyao/StudioProjects/finclip-flutter-sdk/","dependencies":["flutter_plugin_android_lifecycle"]}],"macos":[],"linux":[],"windows":[],"web":[]},"dependencyGraph":[{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"mop","dependencies":["flutter_plugin_android_lifecycle"]}],"date_created":"2022-01-04 13:47:58.706248","version":"2.6.0-12.0.pre.553"} \ No newline at end of file diff --git a/example/.gitignore b/example/.gitignore index 2ddde2a..0fa6b67 100644 --- a/example/.gitignore +++ b/example/.gitignore @@ -22,52 +22,25 @@ # Flutter/Dart/Pub related **/doc/api/ +**/ios/Flutter/.last_build_id .dart_tool/ .flutter-plugins +.flutter-plugins-dependencies .packages .pub-cache/ .pub/ /build/ -# Android related -**/android/**/gradle-wrapper.jar -**/android/.gradle -**/android/captures/ -**/android/gradlew -**/android/gradlew.bat -**/android/local.properties -**/android/**/GeneratedPluginRegistrant.java +# Web related +lib/generated_plugin_registrant.dart -# iOS/XCode related -**/ios/**/*.mode1v3 -**/ios/**/*.mode2v3 -**/ios/**/*.moved-aside -**/ios/**/*.pbxuser -**/ios/**/*.perspectivev3 -**/ios/**/*sync/ -**/ios/**/.sconsign.dblite -**/ios/**/.tags* -**/ios/**/.vagrant/ -**/ios/**/DerivedData/ -**/ios/**/Icon? -**/ios/**/Pods/ -**/ios/**/.symlinks/ -**/ios/**/profile -**/ios/**/xcuserdata -**/ios/.generated/ -**/ios/Flutter/App.framework -**/ios/Flutter/Flutter.framework -**/ios/Flutter/Generated.xcconfig -**/ios/Flutter/app.flx -**/ios/Flutter/app.zip -**/ios/Flutter/flutter_assets/ -**/ios/Flutter/flutter_export_environment.sh -**/ios/ServiceDefinitions.json -**/ios/Runner/GeneratedPluginRegistrant.* +# Symbolication related +app.*.symbols -# Exceptions to above rules. -!**/ios/**/default.mode1v3 -!**/ios/**/default.mode2v3 -!**/ios/**/default.pbxuser -!**/ios/**/default.perspectivev3 -!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/example/.metadata b/example/.metadata index 386075d..0f055bf 100644 --- a/example/.metadata +++ b/example/.metadata @@ -4,7 +4,7 @@ # This file should be version controlled and should not be manually edited. version: - revision: 1aedbb1835bd6eb44550293d57d4d124f19901f0 + revision: ffb2ecea5223acdd139a5039be2f9c796962833d channel: stable project_type: app diff --git a/example/analysis_options.yaml b/example/analysis_options.yaml new file mode 100644 index 0000000..61b6c4d --- /dev/null +++ b/example/analysis_options.yaml @@ -0,0 +1,29 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at + # https://dart-lang.github.io/linter/lints/index.html. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/example/android/.gitignore b/example/android/.gitignore new file mode 100644 index 0000000..6f56801 --- /dev/null +++ b/example/android/.gitignore @@ -0,0 +1,13 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java + +# Remember to never publicly share your keystore. +# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +key.properties +**/*.keystore +**/*.jks diff --git a/example/android/.project b/example/android/.project new file mode 100644 index 0000000..b87df96 --- /dev/null +++ b/example/android/.project @@ -0,0 +1,28 @@ + + + android + Project android created by Buildship. + + + + + org.eclipse.buildship.core.gradleprojectbuilder + + + + + + org.eclipse.buildship.core.gradleprojectnature + + + + 1633860434667 + + 30 + + org.eclipse.core.resources.regexFilterMatcher + node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ + + + + diff --git a/example/android/.settings/org.eclipse.buildship.core.prefs b/example/android/.settings/org.eclipse.buildship.core.prefs new file mode 100644 index 0000000..a1eaa33 --- /dev/null +++ b/example/android/.settings/org.eclipse.buildship.core.prefs @@ -0,0 +1,13 @@ +arguments= +auto.sync=false +build.scans.enabled=false +connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER) +connection.project.dir= +eclipse.preferences.version=1 +gradle.user.home= +java.home=C\:/Program Files/Eclipse Foundation/jdk-11.0.12.7-hotspot +jvm.arguments= +offline.mode=false +override.workspace.settings=true +show.console.view=true +show.executions.view=true diff --git a/example/android/app/.classpath b/example/android/app/.classpath new file mode 100644 index 0000000..4a04201 --- /dev/null +++ b/example/android/app/.classpath @@ -0,0 +1,6 @@ + + + + + + diff --git a/example/android/app/.project b/example/android/app/.project new file mode 100644 index 0000000..1f8babd --- /dev/null +++ b/example/android/app/.project @@ -0,0 +1,34 @@ + + + app + Project app created by Buildship. + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.buildship.core.gradleprojectbuilder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.buildship.core.gradleprojectnature + + + + 1633860434672 + + 30 + + org.eclipse.core.resources.regexFilterMatcher + node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ + + + + diff --git a/example/android/app/.settings/org.eclipse.buildship.core.prefs b/example/android/app/.settings/org.eclipse.buildship.core.prefs new file mode 100644 index 0000000..b1886ad --- /dev/null +++ b/example/android/app/.settings/org.eclipse.buildship.core.prefs @@ -0,0 +1,2 @@ +connection.project.dir=.. +eclipse.preferences.version=1 diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index 8b1ae42..d6d0a81 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -25,20 +25,20 @@ apply plugin: 'com.android.application' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" android { - compileSdkVersion 28 + compileSdkVersion 30 - lintOptions { - disable 'InvalidPackage' + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 } defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "com.finogeeks.mopexample" + applicationId "com.finogeeks.mop_example" minSdkVersion 21 - targetSdkVersion 28 + targetSdkVersion 30 versionCode flutterVersionCode.toInteger() versionName flutterVersionName - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { @@ -48,22 +48,8 @@ android { signingConfig signingConfigs.debug } } - - packagingOptions { - // libsdkcore.so是被加固过的,不能被压缩,否则加载动态库时会报错 - doNotStrip "*/x86/libsdkcore.so" - doNotStrip "*/x86_64/libsdkcore.so" - doNotStrip "*/armeabi-v7a/libsdkcore.so" - doNotStrip "*/arm64-v8a/libsdkcore.so" - } } flutter { source '../..' } - -dependencies { - testImplementation 'junit:junit:4.12' - androidTestImplementation 'androidx.test:runner:1.1.0' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0' -} \ No newline at end of file diff --git a/example/android/app/src/debug/gen/com/finogeeks/mop_example/Manifest.java b/example/android/app/src/debug/gen/com/finogeeks/mop_example/Manifest.java deleted file mode 100644 index 59184ce..0000000 --- a/example/android/app/src/debug/gen/com/finogeeks/mop_example/Manifest.java +++ /dev/null @@ -1,7 +0,0 @@ -/*___Generated_by_IDEA___*/ - -package com.finogeeks.mop_example; - -/* This stub is only used by the IDE. It is NOT the Manifest class actually packed into the APK */ -public final class Manifest { -} \ No newline at end of file diff --git a/example/android/app/src/debug/gen/com/finogeeks/mop_example/R.java b/example/android/app/src/debug/gen/com/finogeeks/mop_example/R.java deleted file mode 100644 index 928e6be..0000000 --- a/example/android/app/src/debug/gen/com/finogeeks/mop_example/R.java +++ /dev/null @@ -1,7 +0,0 @@ -/*___Generated_by_IDEA___*/ - -package com.finogeeks.mop_example; - -/* This stub is only used by the IDE. It is NOT the R class actually packed into the APK */ -public final class R { -} \ No newline at end of file diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml index f44f8ea..77c19dc 100644 --- a/example/android/app/src/main/AndroidManifest.xml +++ b/example/android/app/src/main/AndroidManifest.xml @@ -1,33 +1,41 @@ - - - - + + android:name="io.flutter.embedding.android.NormalTheme" + android:resource="@style/NormalTheme" + /> + + + + diff --git a/example/android/app/src/main/gen/com/finogeeks/mop_example/Manifest.java b/example/android/app/src/main/gen/com/finogeeks/mop_example/Manifest.java deleted file mode 100644 index 59184ce..0000000 --- a/example/android/app/src/main/gen/com/finogeeks/mop_example/Manifest.java +++ /dev/null @@ -1,7 +0,0 @@ -/*___Generated_by_IDEA___*/ - -package com.finogeeks.mop_example; - -/* This stub is only used by the IDE. It is NOT the Manifest class actually packed into the APK */ -public final class Manifest { -} \ No newline at end of file diff --git a/example/android/app/src/main/gen/com/finogeeks/mop_example/R.java b/example/android/app/src/main/gen/com/finogeeks/mop_example/R.java deleted file mode 100644 index 928e6be..0000000 --- a/example/android/app/src/main/gen/com/finogeeks/mop_example/R.java +++ /dev/null @@ -1,7 +0,0 @@ -/*___Generated_by_IDEA___*/ - -package com.finogeeks.mop_example; - -/* This stub is only used by the IDE. It is NOT the R class actually packed into the APK */ -public final class R { -} \ No newline at end of file diff --git a/example/android/app/src/main/java/com/finogeeks/mop_example/MainActivity.java b/example/android/app/src/main/java/com/finogeeks/mop_example/MainActivity.java index 55673ec..7260a2c 100644 --- a/example/android/app/src/main/java/com/finogeeks/mop_example/MainActivity.java +++ b/example/android/app/src/main/java/com/finogeeks/mop_example/MainActivity.java @@ -1,16 +1,6 @@ package com.finogeeks.mop_example; -import android.os.Bundle; - -import io.flutter.app.FlutterActivity; -import io.flutter.plugins.GeneratedPluginRegistrant; +import io.flutter.embedding.android.FlutterActivity; public class MainActivity extends FlutterActivity { - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - GeneratedPluginRegistrant.registerWith(this); - - - } } diff --git a/example/android/app/src/main/res/drawable-v21/launch_background.xml b/example/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 0000000..f74085f --- /dev/null +++ b/example/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/example/android/app/src/main/res/values-night/styles.xml b/example/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 0000000..449a9f9 --- /dev/null +++ b/example/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/example/android/app/src/main/res/values/styles.xml b/example/android/app/src/main/res/values/styles.xml index 00fa441..d74aa35 100644 --- a/example/android/app/src/main/res/values/styles.xml +++ b/example/android/app/src/main/res/values/styles.xml @@ -1,8 +1,18 @@ - + + diff --git a/example/android/build.gradle b/example/android/build.gradle index 1edbb3f..f27fe03 100644 --- a/example/android/build.gradle +++ b/example/android/build.gradle @@ -1,12 +1,11 @@ - buildscript { repositories { google() - jcenter() + mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:3.5.4' + classpath 'com.android.tools.build:gradle:4.1.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.61" } } @@ -14,15 +13,13 @@ buildscript { allprojects { repositories { google() - jcenter() + mavenCentral() } } rootProject.buildDir = '../build' subprojects { project.buildDir = "${rootProject.buildDir}/${project.name}" -} -subprojects { project.evaluationDependsOn(':app') } diff --git a/example/android/gradle.properties b/example/android/gradle.properties index 3992dbe..94adc3a 100644 --- a/example/android/gradle.properties +++ b/example/android/gradle.properties @@ -1,5 +1,3 @@ -android.enableJetifier=true -android.useAndroidX=true org.gradle.jvmargs=-Xmx1536M - -android.enableR8=true +android.useAndroidX=true +android.enableJetifier=true diff --git a/example/android/gradle/wrapper/gradle-wrapper.properties b/example/android/gradle/wrapper/gradle-wrapper.properties index 63ab3ae..bc6a58a 100644 --- a/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/example/android/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip diff --git a/example/android/proguard-android.txt b/example/android/proguard-android.txt deleted file mode 100644 index e69de29..0000000 diff --git a/example/android/proguard-rules.pro b/example/android/proguard-rules.pro deleted file mode 100644 index 4194f7b..0000000 --- a/example/android/proguard-rules.pro +++ /dev/null @@ -1,5 +0,0 @@ --keep class com.finogeeks.** {*;} - -# tbs --keep class com.tencent.smtt.** {*;} --keep class com.tencent.tbs.** {*;} \ No newline at end of file diff --git a/example/android/settings.gradle b/example/android/settings.gradle index 5a2f14f..44e62bc 100644 --- a/example/android/settings.gradle +++ b/example/android/settings.gradle @@ -1,15 +1,11 @@ include ':app' -def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() +def localPropertiesFile = new File(rootProject.projectDir, "local.properties") +def properties = new Properties() -def plugins = new Properties() -def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') -if (pluginsFile.exists()) { - pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } -} +assert localPropertiesFile.exists() +localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } -plugins.each { name, path -> - def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() - include ":$name" - project(":$name").projectDir = pluginDirectory -} +def flutterSdkPath = properties.getProperty("flutter.sdk") +assert flutterSdkPath != null, "flutter.sdk not set in local.properties" +apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" diff --git a/example/ios/.gitignore b/example/ios/.gitignore new file mode 100644 index 0000000..151026b --- /dev/null +++ b/example/ios/.gitignore @@ -0,0 +1,33 @@ +*.mode1v3 +*.mode2v3 +*.moved-aside +*.pbxuser +*.perspectivev3 +**/*sync/ +.sconsign.dblite +.tags* +**/.vagrant/ +**/DerivedData/ +Icon? +**/Pods/ +**/.symlinks/ +profile +xcuserdata +**/.generated/ +Flutter/App.framework +Flutter/Flutter.framework +Flutter/Flutter.podspec +Flutter/Generated.xcconfig +Flutter/ephemeral/ +Flutter/app.flx +Flutter/app.zip +Flutter/flutter_assets/ +Flutter/flutter_export_environment.sh +ServiceDefinitions.json +Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!default.mode1v3 +!default.mode2v3 +!default.pbxuser +!default.perspectivev3 diff --git a/example/ios/Flutter/.last_build_id b/example/ios/Flutter/.last_build_id deleted file mode 100644 index cc1326f..0000000 --- a/example/ios/Flutter/.last_build_id +++ /dev/null @@ -1 +0,0 @@ -9b8dc99cc1898757c03a06b2261ab8de diff --git a/example/ios/Flutter/AppFrameworkInfo.plist b/example/ios/Flutter/AppFrameworkInfo.plist index 6b4c0f7..8d4492f 100644 --- a/example/ios/Flutter/AppFrameworkInfo.plist +++ b/example/ios/Flutter/AppFrameworkInfo.plist @@ -3,7 +3,7 @@ CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) + en CFBundleExecutable App CFBundleIdentifier @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 8.0 + 9.0 diff --git a/example/ios/Flutter/Debug.xcconfig b/example/ios/Flutter/Debug.xcconfig index e8efba1..ec97fc6 100644 --- a/example/ios/Flutter/Debug.xcconfig +++ b/example/ios/Flutter/Debug.xcconfig @@ -1,2 +1,2 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Generated.xcconfig" diff --git a/example/ios/Flutter/Flutter.podspec b/example/ios/Flutter/Flutter.podspec deleted file mode 100644 index 5ca3041..0000000 --- a/example/ios/Flutter/Flutter.podspec +++ /dev/null @@ -1,18 +0,0 @@ -# -# NOTE: This podspec is NOT to be published. It is only used as a local source! -# - -Pod::Spec.new do |s| - s.name = 'Flutter' - s.version = '1.0.0' - s.summary = 'High-performance, high-fidelity mobile apps.' - s.description = <<-DESC -Flutter provides an easy and productive way to build and deploy high-performance mobile apps for Android and iOS. - DESC - s.homepage = 'https://flutter.io' - s.license = { :type => 'MIT' } - s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' } - s.source = { :git => 'https://github.com/flutter/engine', :tag => s.version.to_s } - s.ios.deployment_target = '8.0' - s.vendored_frameworks = 'Flutter.framework' -end diff --git a/example/ios/Flutter/Release.xcconfig b/example/ios/Flutter/Release.xcconfig index 399e934..c4855bf 100644 --- a/example/ios/Flutter/Release.xcconfig +++ b/example/ios/Flutter/Release.xcconfig @@ -1,2 +1,2 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Generated.xcconfig" diff --git a/example/ios/Podfile b/example/ios/Podfile index b62db64..8933ab5 100644 --- a/example/ios/Podfile +++ b/example/ios/Podfile @@ -1,8 +1,5 @@ # Uncomment this line to define a global platform for your project -# platform :ios, '9.0' - -source 'https://git.finogeeks.club/finoapp-ios/FinPods' -source 'https://github.com/CocoaPods/Specs.git' +platform :ios, '9.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' @@ -13,63 +10,40 @@ project 'Runner', { 'Release' => :release, } -def parse_KV_file(file, separator='=') - file_abs_path = File.expand_path(file) - if !File.exists? file_abs_path - return []; +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" end - pods_ary = [] - skip_line_start_symbols = ["#", "/"] - File.foreach(file_abs_path) { |line| - next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } - plugin = line.split(pattern=separator) - if plugin.length == 2 - podname = plugin[0].strip() - path = plugin[1].strip() - podpath = File.expand_path("#{path}", file_abs_path) - pods_ary.push({:name => podname, :path => podpath}); - else - puts "Invalid plugin specification: #{line}" - end - } - return pods_ary + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" end +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + target 'Runner' do - # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock - # referring to absolute paths on developers' machines. - system('rm -rf .symlinks') - system('mkdir -p .symlinks/plugins') + use_frameworks! + use_modular_headers! - # Flutter Pods - generated_xcode_build_settings = parse_KV_file('./Flutter/Generated.xcconfig') - if generated_xcode_build_settings.empty? - puts "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first." - end - generated_xcode_build_settings.map { |p| - if p[:name] == 'FLUTTER_FRAMEWORK_DIR' - symlink = File.join('.symlinks', 'flutter') - File.symlink(File.dirname(p[:path]), symlink) - pod 'Flutter', :path => File.join(symlink, File.basename(p[:path])) - end - } - - # Plugin Pods - plugin_pods = parse_KV_file('../.flutter-plugins') - plugin_pods.map { |p| - symlink = File.join('.symlinks', 'plugins', p[:name]) - File.symlink(p[:path], symlink) - pod p[:name], :path => File.join(symlink, 'ios') - } + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) end -# Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system. -install! 'cocoapods', :disable_input_output_paths => true - post_install do |installer| installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) target.build_configurations.each do |config| - config.build_settings['ENABLE_BITCODE'] = 'NO' + config.build_settings['EXCLUDED_ARCHS[sdk=iphonesimulator*]'] = 'arm64' + if config.name == "Debug" + config.build_settings['ONLY_ACTIVE_ARCH'] = 'YES' + else + config.build_settings['ONLY_ACTIVE_ARCH'] = 'NO' + end end end end diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 6dc2ef8..c5e7489 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -1,3 +1,34 @@ -PODFILE CHECKSUM: fa591ea0d89752dd0191ae3f82c83db034678e82 +PODS: + - FinApplet (2.34.11) + - FinAppletExt (2.34.11): + - FinApplet (= 2.34.11) + - Flutter (1.0.0) + - mop (0.1.1): + - FinApplet (= 2.34.11) + - FinAppletExt (= 2.34.11) + - Flutter -COCOAPODS: 1.10.1 +DEPENDENCIES: + - Flutter (from `Flutter`) + - mop (from `.symlinks/plugins/mop/ios`) + +SPEC REPOS: + trunk: + - FinApplet + - FinAppletExt + +EXTERNAL SOURCES: + Flutter: + :path: Flutter + mop: + :path: ".symlinks/plugins/mop/ios" + +SPEC CHECKSUMS: + FinApplet: 975a76c8de4c9ddf64d6b4bfcd946ad6830f54f6 + FinAppletExt: 9489276a84f908b60a75a71d09b0b4397e070bee + Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a + mop: 9a49a0b917e4016aa897c76656fddb69ad69b118 + +PODFILE CHECKSUM: 2317ba7584871ae8cd67fd0244fbd5e96fd06167 + +COCOAPODS: 1.11.2 diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index 3bcf55a..2d273a5 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -3,19 +3,17 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 51; objects = { /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; }; - 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; - 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; + 6DB2EFFFC5FD4690C06ACB3A /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B691CF78BE1464D3451E07AF /* Pods_Runner.framework */; }; + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; - AF7B8F29E858B4266D8A8AD0 /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = ABAEB264A095769DC71DEAE1 /* libPods-Runner.a */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -32,24 +30,23 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 073CDBAAF19B6FF1EF196501 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 207F05A0BE4F11BA62008DCF /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 4F9256BFB604D1207B06C14E /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + 6793BBA3F03EE46BEAD75979 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; - 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; - 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 865E64E9FAB2F680272FCE6F /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - ABAEB264A095769DC71DEAE1 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - B62C1456907598F7FC4CC93E /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + B691CF78BE1464D3451E07AF /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -57,17 +54,27 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - AF7B8F29E858B4266D8A8AD0 /* libPods-Runner.a in Frameworks */, + 6DB2EFFFC5FD4690C06ACB3A /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 43950FB4B3EA29B9EA2BA804 /* Frameworks */ = { + 1B5EB5EC57E12758D2A6310E /* Pods */ = { isa = PBXGroup; children = ( - ABAEB264A095769DC71DEAE1 /* libPods-Runner.a */, + 6793BBA3F03EE46BEAD75979 /* Pods-Runner.debug.xcconfig */, + 207F05A0BE4F11BA62008DCF /* Pods-Runner.release.xcconfig */, + 865E64E9FAB2F680272FCE6F /* Pods-Runner.profile.xcconfig */, + ); + path = Pods; + sourceTree = ""; + }; + 8C9832689000ED580600B3AE /* Frameworks */ = { + isa = PBXGroup; + children = ( + B691CF78BE1464D3451E07AF /* Pods_Runner.framework */, ); name = Frameworks; sourceTree = ""; @@ -89,8 +96,8 @@ 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, - 9A4E54748C7B614766AAD771 /* Pods */, - 43950FB4B3EA29B9EA2BA804 /* Frameworks */, + 1B5EB5EC57E12758D2A6310E /* Pods */, + 8C9832689000ED580600B3AE /* Frameworks */, ); sourceTree = ""; }; @@ -105,37 +112,18 @@ 97C146F01CF9000F007C117D /* Runner */ = { isa = PBXGroup; children = ( - 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */, - 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */, 97C146FA1CF9000F007C117D /* Main.storyboard */, 97C146FD1CF9000F007C117D /* Assets.xcassets */, 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 97C147021CF9000F007C117D /* Info.plist */, - 97C146F11CF9000F007C117D /* Supporting Files */, 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, ); path = Runner; sourceTree = ""; }; - 97C146F11CF9000F007C117D /* Supporting Files */ = { - isa = PBXGroup; - children = ( - 97C146F21CF9000F007C117D /* main.m */, - ); - name = "Supporting Files"; - sourceTree = ""; - }; - 9A4E54748C7B614766AAD771 /* Pods */ = { - isa = PBXGroup; - children = ( - 073CDBAAF19B6FF1EF196501 /* Pods-Runner.debug.xcconfig */, - 4F9256BFB604D1207B06C14E /* Pods-Runner.release.xcconfig */, - B62C1456907598F7FC4CC93E /* Pods-Runner.profile.xcconfig */, - ); - path = Pods; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -143,13 +131,14 @@ isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( - BC8240216498EB68CEE5D926 /* [CP] Check Pods Manifest.lock */, + 2DEACE28B1DB5888C31A623A /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + 46BA5F59FC1A40CE8339661F /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -166,17 +155,17 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1020; - ORGANIZATIONNAME = "The Chromium Authors"; + LastUpgradeCheck = 1300; + ORGANIZATIONNAME = ""; TargetAttributes = { 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; - DevelopmentTeam = H48LA2V876; + LastSwiftMigration = 1100; }; }; }; buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 3.2"; + compatibilityVersion = "Xcode 9.3"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( @@ -200,7 +189,6 @@ files = ( 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, - 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */, 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, ); @@ -209,35 +197,7 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Thin Binary"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; - }; - 9740EEB61CF901F6004384FC /* Run Script */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Run Script"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; - }; - BC8240216498EB68CEE5D926 /* [CP] Check Pods Manifest.lock */ = { + 2DEACE28B1DB5888C31A623A /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -259,6 +219,51 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 46BA5F59FC1A40CE8339661F /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -266,8 +271,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */, - 97C146F31CF9000F007C117D /* main.m in Sources */, + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -338,6 +342,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 9.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; @@ -348,23 +353,18 @@ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = H48LA2V876; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); INFOPLIST_FILE = Runner/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Flutter", + "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.0; - PRODUCT_BUNDLE_IDENTIFIER = com.finogeeks.mopexample; + PRODUCT_BUNDLE_IDENTIFIER = com.finogeeks.finclip.demo; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; }; name = Profile; @@ -468,6 +468,8 @@ IPHONEOS_DEPLOYMENT_TARGET = 9.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; @@ -478,23 +480,19 @@ baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = H48LA2V876; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); INFOPLIST_FILE = Runner/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Flutter", + "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.0; - PRODUCT_BUNDLE_IDENTIFIER = com.finogeeks.mopexample; + PRODUCT_BUNDLE_IDENTIFIER = com.finogeeks.finclip.demo; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; }; name = Debug; @@ -504,23 +502,18 @@ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = H48LA2V876; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); INFOPLIST_FILE = Runner/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Flutter", + "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.0; - PRODUCT_BUNDLE_IDENTIFIER = com.finogeeks.mopexample; + PRODUCT_BUNDLE_IDENTIFIER = com.finogeeks.finclip.demo; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; }; name = Release; diff --git a/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index a28140c..3db53b6 100644 --- a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ + + + + PreviewsEnabled + + + diff --git a/example/ios/Runner/AppDelegate.h b/example/ios/Runner/AppDelegate.h deleted file mode 100644 index 36e21bb..0000000 --- a/example/ios/Runner/AppDelegate.h +++ /dev/null @@ -1,6 +0,0 @@ -#import -#import - -@interface AppDelegate : FlutterAppDelegate - -@end diff --git a/example/ios/Runner/AppDelegate.m b/example/ios/Runner/AppDelegate.m deleted file mode 100644 index 59a72e9..0000000 --- a/example/ios/Runner/AppDelegate.m +++ /dev/null @@ -1,13 +0,0 @@ -#include "AppDelegate.h" -#include "GeneratedPluginRegistrant.h" - -@implementation AppDelegate - -- (BOOL)application:(UIApplication *)application - didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - [GeneratedPluginRegistrant registerWithRegistry:self]; - // Override point for customization after application launch. - return [super application:application didFinishLaunchingWithOptions:launchOptions]; -} - -@end diff --git a/example/ios/Runner/AppDelegate.swift b/example/ios/Runner/AppDelegate.swift new file mode 100644 index 0000000..70693e4 --- /dev/null +++ b/example/ios/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import UIKit +import Flutter + +@UIApplicationMain +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } +} diff --git a/example/ios/Runner/Info.plist b/example/ios/Runner/Info.plist index cb8c961..1293dcb 100644 --- a/example/ios/Runner/Info.plist +++ b/example/ios/Runner/Info.plist @@ -15,11 +15,11 @@ CFBundlePackageType APPL CFBundleShortVersionString - $(MARKETING_VERSION) + $(FLUTTER_BUILD_NAME) CFBundleSignature ???? CFBundleVersion - $(CURRENT_PROJECT_VERSION) + $(FLUTTER_BUILD_NUMBER) LSRequiresIPhoneOS UILaunchStoryboardName diff --git a/example/ios/Runner/Runner-Bridging-Header.h b/example/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 0000000..308a2a5 --- /dev/null +++ b/example/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/example/ios/Runner/main.m b/example/ios/Runner/main.m deleted file mode 100644 index dff6597..0000000 --- a/example/ios/Runner/main.m +++ /dev/null @@ -1,9 +0,0 @@ -#import -#import -#import "AppDelegate.h" - -int main(int argc, char* argv[]) { - @autoreleasepool { - return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); - } -} diff --git a/example/lib/main.dart b/example/lib/main.dart index b488f98..e212afc 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,3 +1,7 @@ +// ignore_for_file: prefer_const_constructors + +import 'dart:ffi'; + import 'package:flutter/material.dart'; import 'dart:async'; import 'dart:io'; @@ -19,20 +23,120 @@ class _MyAppState extends State { // Platform messages are asynchronous, so we initialize in an async method. Future init() async { + UIConfig uiconfig = UIConfig(); + //多服务器配置 + + FinStoreConfig storeConfigA = FinStoreConfig( + "2LyZEib0gLTQdU3MUauATBwgfnTCJjdr7FCnywmAEM=", + "bdfd76cae24d4313", + "https://api.finclip.com", + "https://api.finclip.com", + ); + + FinStoreConfig storeConfigB = FinStoreConfig( + "2LyZEib0gLTQdU3MUauATBwgfnTCJjdr7FCnywmAEM=", + "bdfd76cae24d4313", + "https://finchat-mop-b.finogeeks.club", + "https://finchat-mop-b.finogeeks.club", + ); + List storeConfigs = [storeConfigA]; + uiconfig.isAlwaysShowBackInDefaultNavigationBar = false; + uiconfig.isClearNavigationBarNavButtonBackground = false; + uiconfig.isHideFeedbackAndComplaints = true; + uiconfig.isHideBackHome = true; + uiconfig.isHideForwardMenu = true; + uiconfig.hideTransitionCloseButton = true; + uiconfig.disableSlideCloseAppletGesture = true; + CapsuleConfig capsuleConfig = CapsuleConfig(); + capsuleConfig.capsuleBgLightColor = 0x33ff00ee; + capsuleConfig.capsuleRightMargin = 25; + uiconfig.capsuleConfig = capsuleConfig; + uiconfig.appletText = "applet"; + if (Platform.isIOS) { final res = await Mop.instance.initialize( - '22LyZEib0gLTQdU3MUauAZ0pZVbKTWGmNN6Lx8hXhIkA', '74bde5fad53a817c', - apiServer: 'https://api.finclip.com', apiPrefix: '/api/v1/mop'); + '22LyZEib0gLTQdU3MUauATBwgfnTCJjdr7FCnywmAEM=', 'bdfd76cae24d4313', + apiServer: 'https://api.finclip.com', + apiPrefix: '/api/v1/mop', + uiConfig: uiconfig, + finStoreConfigs: storeConfigs); print(res); } else if (Platform.isAndroid) { final res = await Mop.instance.initialize( - '22LyZEib0gLTQdU3MUauAZ0pZVbKTWGmNN6Lx8hXhIkA', '74bde5fad53a817c', + '22LyZEib0gLTQdU3MUauATBwgfnTCJjdr7FCnywmAEM=', 'bdfd76cae24d4313', apiServer: 'https://api.finclip.com', apiPrefix: '/api/v1/mop'); print(res); } if (!mounted) return; } + Widget _buildAppletItem( + String appletId, String itemName, VoidCallback tapAction) { + return GestureDetector( + onTap: tapAction, + child: Container( + padding: EdgeInsets.only(left: 7, right: 7), + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(5)), + gradient: LinearGradient( + colors: const [Color(0xFF12767e), Color(0xFF0dabb8)], + stops: const [0.0, 1.0], + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + ), + ), + child: Center( + child: Text( + itemName, + style: TextStyle(color: Colors.white), + ), + ), + ), + ); + } + + Widget _buildAppletWidget(String appletId, String appletName) { + return Container( + margin: EdgeInsets.only(left: 20, top: 30, right: 20), + child: Column( + children: [ + Text( + appletName, + style: TextStyle( + fontSize: 18, fontWeight: FontWeight.w500, color: Colors.red), + ), + SizedBox( + height: 10, + ), + Container( + height: 100, + child: GridView.count( + crossAxisCount: 3, + childAspectRatio: 2, + crossAxisSpacing: 30, + // physics: NeverScrollableScrollPhysics(), + children: [ + _buildAppletItem(appletId, "打开小程序", () { + Mop.instance.openApplet(appletId, + path: 'pages/index/index', query: ''); + }), + _buildAppletItem(appletId, "finishRunningApplet", () { + Mop.instance.finishRunningApplet(appletId, true); + }), + _buildAppletItem(appletId, "removeUsedApplet", () { + Mop.instance.removeUsedApplet(appletId); + }), + // _buildAppletItem(appletId, "removeUsedApplet", () { + // Mop.instance.removeUsedApplet(appletId); + // }), + ], + ), + ) + ], + ), + ); + } + // 5e637a18cbfae4000170fa7a @override Widget build(BuildContext context) { @@ -41,82 +145,12 @@ class _MyAppState extends State { appBar: AppBar( title: const Text('凡泰极客小程序 Flutter 插件'), ), - body: Center( - child: Container( - padding: EdgeInsets.only( - top: 20, - ), - child: Column( - children: [ - Container( - width: 140, - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(5)), - gradient: LinearGradient( - colors: const [Color(0xFF12767e), Color(0xFF0dabb8)], - stops: const [0.0, 1.0], - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - ), - ), - child: FlatButton( - onPressed: () { - Mop.instance.openApplet('5ea03fa563cb900001d73863', - path: 'pages/index/index', query: ''); - }, - child: Text( - '打开画图小程序', - style: TextStyle(color: Colors.white), - ), - ), - ), - SizedBox(height: 30), - Container( - width: 140, - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(5)), - gradient: LinearGradient( - colors: const [Color(0xFF12767e), Color(0xFF0dabb8)], - stops: const [0.0, 1.0], - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - ), - ), - child: FlatButton( - onPressed: () { - Mop.instance.openApplet('5ea0401463cb900001d73865'); - }, - child: Text( - '打开官方小程序', - style: TextStyle(color: Colors.white), - ), - ), - ), - SizedBox(height: 30), - Container( - width: 140, - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(5)), - gradient: LinearGradient( - colors: const [Color(0xFF12767e), Color(0xFF0dabb8)], - stops: const [0.0, 1.0], - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - ), - ), - child: FlatButton( - onPressed: () { - Mop.instance.openApplet('5ea0412663cb900001d73867'); - }, - child: Text( - '我的对账单', - style: TextStyle(color: Colors.white), - ), - ), - ), - ], - ), - ), + body: Column( + children: [ + _buildAppletWidget("5facb3a52dcbff00017469bd", "画图小程序"), + _buildAppletWidget("5fa214a29a6a7900019b5cc1", "官方小程序"), + _buildAppletWidget("5fa215459a6a7900019b5cc3", "我的对账单"), + ], ), ), ); diff --git a/example/pubspec.lock b/example/pubspec.lock index 4d1da1d..bacf03e 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -7,7 +7,7 @@ packages: name: async url: "https://pub.flutter-io.cn" source: hosted - version: "2.6.1" + version: "2.8.2" boolean_selector: dependency: transitive description: @@ -21,14 +21,14 @@ packages: name: characters url: "https://pub.flutter-io.cn" source: hosted - version: "1.1.0" + version: "1.2.0" charcode: dependency: transitive description: name: charcode url: "https://pub.flutter-io.cn" source: hosted - version: "1.2.0" + version: "1.3.1" clock: dependency: transitive description: @@ -49,7 +49,7 @@ packages: name: cupertino_icons url: "https://pub.flutter-io.cn" source: hosted - version: "0.1.3" + version: "1.0.4" fake_async: dependency: transitive description: @@ -62,27 +62,48 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.4" + flutter_plugin_android_lifecycle: + dependency: transitive + description: + name: flutter_plugin_android_lifecycle + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.5" flutter_test: dependency: "direct dev" description: flutter source: sdk version: "0.0.0" + lints: + dependency: transitive + description: + name: lints + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.1" matcher: dependency: transitive description: name: matcher url: "https://pub.flutter-io.cn" source: hosted - version: "0.12.10" + version: "0.12.11" meta: dependency: transitive description: name: meta url: "https://pub.flutter-io.cn" source: hosted - version: "1.3.0" + version: "1.7.0" mop: - dependency: "direct dev" + dependency: "direct main" description: path: ".." relative: true @@ -141,7 +162,7 @@ packages: name: test_api url: "https://pub.flutter-io.cn" source: hosted - version: "0.3.0" + version: "0.4.3" typed_data: dependency: transitive description: @@ -155,7 +176,7 @@ packages: name: vector_math url: "https://pub.flutter-io.cn" source: hosted - version: "2.1.0" + version: "2.1.1" sdks: - dart: ">=2.12.0 <3.0.0" - flutter: ">=1.10.0" + dart: ">=2.14.0 <3.0.0" + flutter: ">=2.2.3" diff --git a/example/pubspec.yaml b/example/pubspec.yaml index bd40a2d..b48267d 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -3,39 +3,57 @@ description: Demonstrates how to use the mop plugin. publish_to: 'none' environment: - sdk: '>=2.1.0 <3.0.0' + sdk: '>=2.12.0 <3.0.0' dependencies: flutter: sdk: flutter + mop: + # When depending on this package from a real application you should use: + # mop: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # The example app is bundled with the plugin so we use a path dependency on + # the parent directory to use the current plugin's version. + path: ../ + # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^0.1.2 + cupertino_icons: ^1.0.2 dev_dependencies: flutter_test: sdk: flutter - mop: - path: ../ + + # The "flutter_lints" package below contains a set of recommended lints to + # encourage good coding practices. The lint set provided by the package is + # activated in the `analysis_options.yaml` file located at the root of your + # package. See that file for information about deactivating specific lint + # rules and activating additional ones. + flutter_lints: ^1.0.0 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec # The following section is specific to Flutter. flutter: + # The following line ensures that the Material Icons font is # included with your application, so that you can use the icons in # the material Icons class. uses-material-design: true + # To add assets to your application, add an assets section, like this: # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/assets-and-images/#resolution-aware. + # For details regarding adding assets from package dependencies, see # https://flutter.dev/assets-and-images/#from-packages + # To add custom fonts to your application, add a fonts section here, # in this "flutter" section. Each entry in this list should have a # "family" key with the font family name, and a "fonts" key with a diff --git a/example/test/widget_test.dart b/example/test/widget_test.dart index 9808a6f..bf7d60e 100644 --- a/example/test/widget_test.dart +++ b/example/test/widget_test.dart @@ -19,7 +19,7 @@ void main() { expect( find.byWidgetPredicate( (Widget widget) => widget is Text && - widget.data.startsWith('Running on:'), + widget.data!.startsWith('Running on:'), ), findsOneWidget, ); diff --git a/ios/Classes/Api/MOB_addWebExtentionApi.h b/ios/Classes/Api/MOB_addWebExtentionApi.h new file mode 100644 index 0000000..d33d50d --- /dev/null +++ b/ios/Classes/Api/MOB_addWebExtentionApi.h @@ -0,0 +1,16 @@ +// +// MOB_addWebExtentionApi.h +// mop +// +// Created by 王滔 on 2021/12/21. +// + +#import "MOPBaseApi.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface MOB_addWebExtentionApi : MOPBaseApi +@property(nonatomic, copy) NSString* name; +@end + +NS_ASSUME_NONNULL_END diff --git a/ios/Classes/Api/MOB_addWebExtentionApi.m b/ios/Classes/Api/MOB_addWebExtentionApi.m new file mode 100644 index 0000000..ba81192 --- /dev/null +++ b/ios/Classes/Api/MOB_addWebExtentionApi.m @@ -0,0 +1,53 @@ +// +// MOB_addWebExtentionApi.m +// mop +// +// Created by 王滔 on 2021/12/21. +// + +#import "MOB_addWebExtentionApi.h" +#import "MopPlugin.h" +#import + +@implementation MOB_addWebExtentionApi + +- (void)setupApiWithSuccess:(void (^)(NSDictionary * _Nonnull))success failure:(void (^)(id _Nullable))failure cancel:(void (^)(void))cancel +{ + NSLog(@"MOB_addWebExtentionApi"); + FlutterMethodChannel *channel = [[MopPlugin instance] methodChannel]; + [[FATClient sharedClient] fat_registerWebApi:self.name handle:^(id param, FATExtensionApiCallback callback) { + NSLog(@"invoke webExtentionApi:"); + NSLog(@"%@",self.name); + NSLog(@"%@",param); + NSString* api = [@"webExtentionApi:" stringByAppendingString:self.name]; + [channel invokeMethod:api arguments:param result:^(id _Nullable result) { + NSLog(@"webExtentionApi reslut:%@",result); + // 先判断是否flutter发生错误 + BOOL isFlutterError = [result isKindOfClass:[FlutterError class]] || result == FlutterMethodNotImplemented; + if (isFlutterError) { + NSLog(@"webExtentionApi reslut:fail"); + callback(FATExtensionCodeFailure,nil); + return; + } + // 再判断回调是否为失败 + BOOL hasError = [[result allKeys] containsObject:@"errMsg"]; + if (hasError) { + NSString *errMsg = result[@"errMsg"]; + NSString *errPrefix = [NSString stringWithFormat:@"%@:fail", self.name]; + BOOL isFail = [errMsg hasPrefix:errPrefix]; + if (isFail) { + NSLog(@"webExtentionApi reslut:fail"); + callback(FATExtensionCodeFailure,nil); + return; + } + } + // 其他的按成功处理 + NSLog(@"webExtentionApi callback:%@",result); + callback(FATExtensionCodeSuccess,result); + }]; + + }]; + success(@{}); + +} +@end diff --git a/ios/Classes/Api/MOP_callJS.h b/ios/Classes/Api/MOP_callJS.h new file mode 100644 index 0000000..aa0c9ad --- /dev/null +++ b/ios/Classes/Api/MOP_callJS.h @@ -0,0 +1,18 @@ +// +// MOP_callJS.h +// mop +// +// Created by 王滔 on 2021/12/21. +// + +#import "MOPBaseApi.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface MOP_callJS : MOPBaseApi +@property (nonatomic, copy) NSString *eventName; +@property (nonatomic, copy) NSString *nativeViewId; +@property (nonatomic, copy) NSDictionary *eventData; +@end + +NS_ASSUME_NONNULL_END diff --git a/ios/Classes/Api/MOP_callJS.m b/ios/Classes/Api/MOP_callJS.m new file mode 100644 index 0000000..07be0e4 --- /dev/null +++ b/ios/Classes/Api/MOP_callJS.m @@ -0,0 +1,28 @@ +// +// MOP_callJS.m +// mop +// +// Created by 王滔 on 2021/12/21. +// + +#import "MOP_callJS.h" + +@implementation MOP_callJS + +- (void)setupApiWithSuccess:(void (^)(NSDictionary * _Nonnull))success failure:(void (^)(id _Nullable))failure cancel:(void (^)(void))cancel +{ + if (!self.eventData || !self.eventName || !self.nativeViewId) { + failure(@{@"errMsg": @"callJS:fail"}); + return; + } + + NSNumber *numberId = @(_nativeViewId.integerValue); + [[FATClient sharedClient].nativeViewManager sendEvent:_eventName nativeViewId:numberId detail:_eventData completion:^(id result, NSError *error) { + if (error) { + failure(@{@"errMsg": @"sendCustomEvent:fail"}); + } else { + success(result); + } + }]; +} +@end diff --git a/ios/Classes/Api/MOP_closeApplet.h b/ios/Classes/Api/MOP_closeApplet.h new file mode 100644 index 0000000..b87fb22 --- /dev/null +++ b/ios/Classes/Api/MOP_closeApplet.h @@ -0,0 +1,17 @@ +// +// MOP_closeApplet.h +// mop +// +// Created by 王滔 on 2021/12/21. +// + +#import "MOPBaseApi.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface MOP_closeApplet : MOPBaseApi +@property (nonatomic, copy) NSString *appletId; +@property (nonatomic, assign) BOOL animated; +@end + +NS_ASSUME_NONNULL_END diff --git a/ios/Classes/Api/MOP_closeApplet.m b/ios/Classes/Api/MOP_closeApplet.m new file mode 100644 index 0000000..292f21a --- /dev/null +++ b/ios/Classes/Api/MOP_closeApplet.m @@ -0,0 +1,25 @@ +// +// MOP_closeApplet.m +// mop +// +// Created by 王滔 on 2021/12/21. +// + +#import "MOP_closeApplet.h" +#import + +@implementation MOP_closeApplet + +- (void)setupApiWithSuccess:(void (^)(NSDictionary * _Nonnull))success failure:(void (^)(id _Nullable))failure cancel:(void (^)(void))cancel +{ + if (!self.appletId || self.appletId.length < 1) { + failure(@{@"errMsg": @"closeApplet:fail"}); + return; + } + [[FATClient sharedClient] closeApplet:self.appletId animated:_animated completion:^{ + success(@{}); + }]; + +} + +@end diff --git a/ios/Classes/Api/MOP_finishRunningApplet.h b/ios/Classes/Api/MOP_finishRunningApplet.h new file mode 100644 index 0000000..33a1cc2 --- /dev/null +++ b/ios/Classes/Api/MOP_finishRunningApplet.h @@ -0,0 +1,17 @@ +// +// MOP_finishRunningApplet.h +// mop +// +// Created by 王滔 on 2021/12/21. +// + +#import "MOPBaseApi.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface MOP_finishRunningApplet : MOPBaseApi +@property (nonatomic, copy) NSString *appletId; +@property (nonatomic, assign) BOOL animated; +@end + +NS_ASSUME_NONNULL_END diff --git a/ios/Classes/Api/MOP_finishRunningApplet.m b/ios/Classes/Api/MOP_finishRunningApplet.m new file mode 100644 index 0000000..3d1f6f5 --- /dev/null +++ b/ios/Classes/Api/MOP_finishRunningApplet.m @@ -0,0 +1,25 @@ +// +// MOP_finishRunningApplet.m +// mop +// +// Created by 王滔 on 2021/12/21. +// + +#import "MOP_finishRunningApplet.h" + +@implementation MOP_finishRunningApplet + +- (void)setupApiWithSuccess:(void (^)(NSDictionary * _Nonnull))success failure:(void (^)(id _Nullable))failure cancel:(void (^)(void))cancel +{ + if (!self.appletId || self.appletId.length < 1) { + failure(@{@"errMsg": @"finishRunningApplet:fail"}); + return; + } + [[FATClient sharedClient] closeApplet:self.appletId animated:_animated completion:^{ + [[FATClient sharedClient] clearMemeryApplet:self.appletId]; + success(@{}); + }]; + +} + +@end diff --git a/ios/Classes/Api/MOP_initialize.h b/ios/Classes/Api/MOP_initialize.h index 349c5a3..564f792 100644 --- a/ios/Classes/Api/MOP_initialize.h +++ b/ios/Classes/Api/MOP_initialize.h @@ -16,9 +16,15 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, copy) NSString *apiServer; @property (nonatomic, copy) NSString *apiPrefix; @property (nonatomic, copy) NSString *cryptType; -@property (nonatomic, copy) NSString *userId; -@property (nonatomic, assign) BOOL disablePermission; @property (nonatomic, assign) BOOL encryptServerData; +@property (nonatomic, copy) NSString *userId; +@property (nonatomic, strong) NSArray *finStoreConfigs; +@property (nonatomic, strong) NSDictionary *uiConfig; +@property (nonatomic, copy) NSString *customWebViewUserAgent; +@property (nonatomic, assign) BOOL disablePermission; +@property (nonatomic, assign) NSInteger appletIntervalUpdateLimit; +@property (nonatomic, assign) NSInteger maxRunningApplet; + @end diff --git a/ios/Classes/Api/MOP_initialize.m b/ios/Classes/Api/MOP_initialize.m index 428b045..52ce818 100644 --- a/ios/Classes/Api/MOP_initialize.m +++ b/ios/Classes/Api/MOP_initialize.m @@ -8,15 +8,15 @@ #import "MOP_initialize.h" #import #import -#import -#import +#import "MOPTools.h" +// #import @implementation MOP_initialize - (void)setupApiWithSuccess:(void (^)(NSDictionary * _Nonnull))success failure:(void (^)(id _Nullable))failure cancel:(void (^)(void))cancel { if (!self.appkey || !self.secret) { - failure(@"appkey 或 secret不能为空"); + failure(@"sdkkey 或 secret不能为空"); return; } if (!self.apiServer || [self.apiServer isEqualToString:@""]) { @@ -25,27 +25,102 @@ if (!self.apiPrefix|| [self.apiPrefix isEqualToString:@""]) { self.apiPrefix = @"/api/v1/mop"; } - FATConfig *config = [FATConfig configWithAppSecret:self.secret appKey:self.appkey]; - config.apiServer = [self.apiServer copy]; - config.apiPrefix = [self.apiPrefix copy]; - if([self.cryptType isEqualToString: @"SM"]) - { - config.cryptType = FATApiCryptTypeSM; + FATConfig *config; + if (_finStoreConfigs && _finStoreConfigs.count > 0) { + NSMutableArray *storeArrayM = [NSMutableArray array]; + for (NSDictionary *dict in _finStoreConfigs) { + FATStoreConfig *storeConfig = [[FATStoreConfig alloc] init]; + storeConfig.sdkKey = dict[@"sdkKey"]; + // storeConfig.sdkKey = @"22LyZEib0gLTQdU3MUauAb4V4W8Uxd/gMgmH8Hg1bGQ="; + storeConfig.sdkSecret = dict[@"sdkSecret"]; + storeConfig.apiServer = dict[@"apiServer"]; + storeConfig.apmServer = dict[@"apmServer"]; + storeConfig.fingerprint = dict[@"fingerprint"]; + if ([@"SM" isEqualToString:dict[@"cryptType"]]) { + storeConfig.cryptType = FATApiCryptTypeSM; + } else { + storeConfig.cryptType = FATApiCryptTypeMD5; + } + storeConfig.encryptServerData = [dict[@"encryptServerData"] boolValue]; + [storeArrayM addObject:storeConfig]; + } + config = [FATConfig configWithStoreConfigs:storeArrayM]; + } else { + config = [FATConfig configWithAppSecret:self.secret appKey:self.appkey]; + config.apiServer = [self.apiServer copy]; + config.apiPrefix = [self.apiPrefix copy]; + if([self.cryptType isEqualToString: @"SM"]) + { + config.cryptType = FATApiCryptTypeSM; + } + else + { + config.cryptType = FATApiCryptTypeMD5; + } + + // encryptServerData + NSLog(@"encryptServerData:%d",self.encryptServerData); + config.encryptServerData = self.encryptServerData; } - else - { - config.cryptType = FATApiCryptTypeMD5; - } - config.currentUserId = [self.userId copy]; - // encryptServerData - NSLog(@"encryptServerData:%d",self.encryptServerData); - config.encryptServerData = self.encryptServerData; - + NSLog(@"disablePermission:%d",self.disablePermission); config.disableAuthorize = self.disablePermission; + config.currentUserId = [self.userId copy]; + config.appletIntervalUpdateLimit = self.appletIntervalUpdateLimit; + +// bool debug = false, +// bool bindAppletWithMainProcess = false, +// List? finStoreConfigs, +// UIConfig? uiConfig, +// String? customWebViewUserAgent, +// int appletIntervalUpdateLimit = 0, +// int maxRunningApplet = 5, + NSError* error = nil; FATUIConfig *uiconfig = [[FATUIConfig alloc]init]; uiconfig.autoAdaptDarkMode = YES; + if (_uiConfig) { + if (_uiConfig[@"navigationTitleTextAttributes"]) { + uiconfig.navigationTitleTextAttributes = _uiConfig[@"navigationTitleTextAttributes"]; + } + if (_uiConfig[@"progressBarColor"]) { + uiconfig.progressBarColor = [MOPTools colorWithRGBHex:[_uiConfig[@"progressBarColor"] intValue]]; + } + uiconfig.hideBackToHome = [_uiConfig[@"isHideBackHome"] boolValue]; + uiconfig.hideFeedbackMenu = [_uiConfig[@"isHideFeedbackAndComplaints"] boolValue]; + uiconfig.hideForwardMenu = [_uiConfig[@"isHideForwardMenu"] boolValue]; + uiconfig.autoAdaptDarkMode = [_uiConfig[@"autoAdaptDarkMode"] boolValue]; + + uiconfig.appletText = _uiConfig[@"appletText"]; + uiconfig.hideTransitionCloseButton = [_uiConfig[@"hideTransitionCloseButton"] boolValue]; + uiconfig.disableSlideCloseAppletGesture = _uiConfig[@"disableSlideCloseAppletGesture"]; + if (_uiConfig[@"capsuleConfig"]) { + NSDictionary *capsuleConfigDic = _uiConfig[@"capsuleConfig"]; + FATCapsuleConfig *capsuleConfig = [[FATCapsuleConfig alloc]init]; + capsuleConfig.capsuleWidth = [capsuleConfigDic[@"capsuleWidth"] floatValue]; + capsuleConfig.capsuleHeight = [capsuleConfigDic[@"capsuleHeight"] floatValue]; + capsuleConfig.capsuleRightMargin = [capsuleConfigDic[@"capsuleRightMargin"] floatValue]; + capsuleConfig.capsuleCornerRadius = [capsuleConfigDic[@"capsuleCornerRadius"] floatValue]; + capsuleConfig.capsuleBorderWidth = [capsuleConfigDic[@"capsuleBorderWidth"] floatValue]; + capsuleConfig.moreBtnWidth = [capsuleConfigDic[@"moreBtnWidth"] floatValue]; + capsuleConfig.moreBtnLeftMargin = [capsuleConfigDic[@"moreBtnLeftMargin"] floatValue]; + capsuleConfig.closeBtnWidth = [capsuleConfigDic[@"closeBtnWidth"] floatValue]; + capsuleConfig.closeBtnLeftMargin = [capsuleConfigDic[@"closeBtnLeftMargin"] floatValue]; + + + capsuleConfig.capsuleBorderLightColor = [MOPTools colorWithRGBHex:[capsuleConfigDic[@"capsuleBorderLightColor"] intValue]]; + capsuleConfig.capsuleBorderDarkColor = [MOPTools colorWithRGBHex:[capsuleConfigDic[@"capsuleBorderDarkColor"] intValue]]; + capsuleConfig.capsuleBgLightColor = [MOPTools colorWithRGBHex:[capsuleConfigDic[@"capsuleBgLightColor"] intValue]]; + capsuleConfig.capsuleBgDarkColor = [MOPTools colorWithRGBHex:[capsuleConfigDic[@"capsuleBgDarkColor"] intValue]]; + capsuleConfig.capsuleDividerLightColor = [MOPTools colorWithRGBHex:[capsuleConfigDic[@"capsuleDividerLightColor"] intValue]]; + capsuleConfig.capsuleDividerDarkColor = [MOPTools colorWithRGBHex:[capsuleConfigDic[@"capsuleDividerDarkColor"] intValue]]; + uiconfig.capsuleConfig = capsuleConfig; + + } + + } + uiconfig.appendingCustomUserAgent = self.customWebViewUserAgent; + // uiconfig.moreMenuStyle = FATMoreViewStyleNormal; [[FATClient sharedClient] initWithConfig:config uiConfig:uiconfig error:&error]; if (error) { @@ -55,9 +130,9 @@ // [[FATExtClient sharedClient] fat_prepareExtensionApis]; // [[FATExtClient sharedClient] fat_UsingMapType:@"FATExtMapStyleGD" MapKey:@"6f0f28c4138cbaa51aa5890e26996ea2"]; - [FATGDMapComponent setGDMapAppKey:@"6f0f28c4138cbaa51aa5890e26996ea2"]; + // [FATGDMapComponent setGDMapAppKey:@"6f0f28c4138cbaa51aa5890e26996ea2"]; [[FATClient sharedClient] setEnableLog:YES]; - [FATWebRTCComponent registerComponent]; + // [FATWebRTCComponent registerComponent]; success(@{}); diff --git a/ios/Classes/Api/MOP_registerExtensionApi.h b/ios/Classes/Api/MOP_registerExtensionApi.h index 0cd9fe5..e489f94 100644 --- a/ios/Classes/Api/MOP_registerExtensionApi.h +++ b/ios/Classes/Api/MOP_registerExtensionApi.h @@ -11,7 +11,7 @@ NS_ASSUME_NONNULL_BEGIN @interface MOP_registerExtensionApi : MOPBaseApi -@property NSString* name; +@property(nonatomic, copy) NSString* name; @end diff --git a/ios/Classes/Api/MOP_removeApplet.h b/ios/Classes/Api/MOP_removeApplet.h new file mode 100644 index 0000000..eae034b --- /dev/null +++ b/ios/Classes/Api/MOP_removeApplet.h @@ -0,0 +1,16 @@ +// +// MOP_removeApplet.h +// mop +// +// Created by 王滔 on 2021/12/21. +// + +#import "MOPBaseApi.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface MOP_removeApplet : MOPBaseApi +@property (nonatomic, copy) NSString *appletId; +@end + +NS_ASSUME_NONNULL_END diff --git a/ios/Classes/Api/MOP_removeApplet.m b/ios/Classes/Api/MOP_removeApplet.m new file mode 100644 index 0000000..5b11dcf --- /dev/null +++ b/ios/Classes/Api/MOP_removeApplet.m @@ -0,0 +1,32 @@ +// +// MOP_removeApplet.m +// mop +// +// Created by 王滔 on 2021/12/21. +// + +#import "MOP_removeApplet.h" + +@implementation MOP_removeApplet + +- (void)setupApiWithSuccess:(void (^)(NSDictionary * _Nonnull))success failure:(void (^)(id _Nullable))failure cancel:(void (^)(void))cancel +{ + if (!self.appletId || self.appletId.length < 1) { + failure(@{@"errMsg": @"removeApplet:fail"}); + return; + } + FATAppletInfo *appletInfo = [[FATClient sharedClient] currentApplet]; + if (appletInfo && [appletInfo.appId isEqual:self.appletId]) { + [[FATClient sharedClient] closeApplet:self.appletId animated:NO completion:^{ + [[FATClient sharedClient] removeAppletFromLocalCache:self.appletId]; + success(@{}); + }]; + } else { + [[FATClient sharedClient] removeAppletFromLocalCache:self.appletId]; + success(@{}); + } + + + +} +@end diff --git a/ios/Classes/Api/MOP_sendCustomEvent.h b/ios/Classes/Api/MOP_sendCustomEvent.h new file mode 100644 index 0000000..39436be --- /dev/null +++ b/ios/Classes/Api/MOP_sendCustomEvent.h @@ -0,0 +1,16 @@ +// +// MOP_sendCustomEvent.h +// mop +// +// Created by 王滔 on 2021/12/21. +// + +#import "MOPBaseApi.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface MOP_sendCustomEvent : MOPBaseApi +@property (nonatomic, strong) NSDictionary *eventData; +@end + +NS_ASSUME_NONNULL_END diff --git a/ios/Classes/Api/MOP_sendCustomEvent.m b/ios/Classes/Api/MOP_sendCustomEvent.m new file mode 100644 index 0000000..4642b06 --- /dev/null +++ b/ios/Classes/Api/MOP_sendCustomEvent.m @@ -0,0 +1,28 @@ +// +// MOP_sendCustomEvent.m +// mop +// +// Created by 王滔 on 2021/12/21. +// + +#import "MOP_sendCustomEvent.h" + +@implementation MOP_sendCustomEvent + +- (void)setupApiWithSuccess:(void (^)(NSDictionary * _Nonnull))success failure:(void (^)(id _Nullable))failure cancel:(void (^)(void))cancel +{ + if (!self.eventData ) { + failure(@{@"errMsg": @"sendCustomEvent:fail"}); + return; + } + + [[FATClient sharedClient].nativeViewManager sendCustomEventWithDetail:self.eventData completion:^(id result, NSError *error) { + if (error) { + failure(@{@"errMsg": @"sendCustomEvent:fail"}); + } else { + success(result); + } + }]; + +} +@end diff --git a/ios/Classes/Api/MOP_setFinStoreConfigs.h b/ios/Classes/Api/MOP_setFinStoreConfigs.h new file mode 100644 index 0000000..d2b55ad --- /dev/null +++ b/ios/Classes/Api/MOP_setFinStoreConfigs.h @@ -0,0 +1,16 @@ +// +// MOP_setFinStoreConfigs.h +// mop +// +// Created by 王滔 on 2021/12/20. +// + +#import "MOPBaseApi.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface MOP_setFinStoreConfigs : MOPBaseApi +@property(nonatomic, strong) NSArray *storeConfigs; +@end + +NS_ASSUME_NONNULL_END diff --git a/ios/Classes/Api/MOP_setFinStoreConfigs.m b/ios/Classes/Api/MOP_setFinStoreConfigs.m new file mode 100644 index 0000000..ffc562e --- /dev/null +++ b/ios/Classes/Api/MOP_setFinStoreConfigs.m @@ -0,0 +1,12 @@ +// +// MOP_setFinStoreConfigs.m +// mop +// +// Created by 王滔 on 2021/12/20. +// + +#import "MOP_setFinStoreConfigs.h" + +@implementation MOP_setFinStoreConfigs + +@end diff --git a/ios/Classes/Api/MOP_webViewBounces.h b/ios/Classes/Api/MOP_webViewBounces.h index 0d15f9b..3f4afde 100644 --- a/ios/Classes/Api/MOP_webViewBounces.h +++ b/ios/Classes/Api/MOP_webViewBounces.h @@ -12,7 +12,7 @@ NS_ASSUME_NONNULL_BEGIN @interface MOP_webViewBounces : MOPBaseApi -@property (nonatomic, assign) BOOL bounces; +@property (nonatomic, assign) bool bounces; @end diff --git a/ios/Classes/MopPlugin.m b/ios/Classes/MopPlugin.m index 12b0d84..87d8074 100644 --- a/ios/Classes/MopPlugin.m +++ b/ios/Classes/MopPlugin.m @@ -113,7 +113,9 @@ static MopPlugin *_instance; return [[FATClient sharedClient] handleOpenURL:url]; } --(BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray> * _Nullable))restorationHandler +- (BOOL)application:(UIApplication*)application + continueUserActivity:(NSUserActivity*)userActivity + restorationHandler:(void (^)(NSArray*))restorationHandler { if ([userActivity.activityType isEqualToString:NSUserActivityTypeBrowsingWeb]) { NSURL *url = userActivity.webpageURL; diff --git a/ios/Classes/Utils/MOPApiConverter.m b/ios/Classes/Utils/MOPApiConverter.m index 1480042..b5796aa 100644 --- a/ios/Classes/Utils/MOPApiConverter.m +++ b/ios/Classes/Utils/MOPApiConverter.m @@ -88,9 +88,10 @@ id value = container[key]; id safetyValue = [self parseFromKeyValue:value]; - if (!safetyValue) + if (!safetyValue) //如果safetyValue是字典或者数组类型,为nil值时设置成空字符串会产生崩溃 { - safetyValue = @""; +// safetyValue = @""; + continue; } [result setObject:safetyValue forKey:key]; } diff --git a/ios/Classes/Utils/MOPTools.h b/ios/Classes/Utils/MOPTools.h index b136dbe..af53889 100644 --- a/ios/Classes/Utils/MOPTools.h +++ b/ios/Classes/Utils/MOPTools.h @@ -13,6 +13,9 @@ NS_ASSUME_NONNULL_BEGIN + (UIViewController *)topViewController; + (UIViewController *)topViewController:(UIViewController *)rootViewController; ++ (UIColor *)colorWithRGBHex:(UInt32)hex; + ++ (UIColor *)fat_colorWithHexString:(NSString *)hexColor; @end NS_ASSUME_NONNULL_END diff --git a/ios/Classes/Utils/MOPTools.m b/ios/Classes/Utils/MOPTools.m index e4cd688..236b2be 100644 --- a/ios/Classes/Utils/MOPTools.m +++ b/ios/Classes/Utils/MOPTools.m @@ -28,4 +28,89 @@ return [self topViewController:presentedViewController]; } ++ (UIColor *)colorWithRGBHex:(UInt32)hex +{ + int a = (hex >> 24) & 0xFF; + int r = (hex >> 16) & 0xFF; + int g = (hex >> 8) & 0xFF; + int b = (hex) & 0xFF; + + return [UIColor colorWithRed:r / 255.0f + green:g / 255.0f + blue:b / 255.0f + alpha:a / 255.0f]; +} + ++ (UIColor *)fat_colorWithHexString:(NSString *)hexColor { + if (!hexColor) return nil; + // 兼容black和white + if ([hexColor compare:@"black" options:NSCaseInsensitiveSearch] == NSOrderedSame) { + return UIColor.blackColor; + } else if ([hexColor compare:@"white" options:NSCaseInsensitiveSearch] == NSOrderedSame) { + return UIColor.whiteColor; + } + + NSString *cString = [[hexColor stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] uppercaseString]; + + if (cString.length == 0) return nil; + if ([cString hasPrefix:@"#"]) cString = [cString substringFromIndex:1]; + if ([cString containsString:@"0X"]) cString = [cString stringByReplacingOccurrencesOfString:@"0X" withString:@""]; + + if (cString.length == 3) { // 3位转成6位 + cString = [NSString stringWithFormat:@"%c%c%c%c%c%c", + [cString characterAtIndex:0], + [cString characterAtIndex:0], + [cString characterAtIndex:1], + [cString characterAtIndex:1], + [cString characterAtIndex:2], + [cString characterAtIndex:2]]; + } + if (cString.length == 4) { // 4位转为8位 + cString = [NSString stringWithFormat:@"%c%c%c%c%c%c%c%c", + [cString characterAtIndex:0], + [cString characterAtIndex:0], + [cString characterAtIndex:1], + [cString characterAtIndex:1], + [cString characterAtIndex:2], + [cString characterAtIndex:2], + [cString characterAtIndex:3], + [cString characterAtIndex:3]]; + } + + NSScanner *scanner = [NSScanner scannerWithString:cString]; + unsigned hexNum; + if (![scanner scanHexInt:&hexNum]) return [UIColor blackColor]; + + if (cString.length == 6) { + return [self fat_colorWithRGBHex:hexNum]; + } else if (cString.length == 8) { + return [self fat_colorWithARGBHex:hexNum]; + } + return nil; +} + ++ (UIColor *)fat_colorWithRGBHex:(UInt32)hex { + int red = (hex >> 16) & 0xFF; + int green = (hex >> 8) & 0xFF; + int blue = (hex)&0xFF; + return [UIColor colorWithRed:red / 255.0f green:green / 255.0f blue:blue / 255.0f alpha:1.0f]; +} + ++ (UIColor *)fat_colorWithRGBAlphaHex:(UInt32)hex { + int red = (hex >> 24) & 0xFF; + int green = (hex >> 16) & 0xFF; + int blue = (hex >> 8) & 0xFF; + int alpha = hex & 0xFF; + return [UIColor colorWithRed:red / 255.0f green:green / 255.0f blue:blue / 255.0f alpha:alpha / 255.0f]; +} + ++ (UIColor *)fat_colorWithARGBHex:(UInt32)hex { + int alpha = (hex >> 24) & 0xFF; + int red = (hex >> 16) & 0xFF; + int green = (hex >> 8) & 0xFF; + int blue = hex & 0xFF; + return [UIColor colorWithRed:red / 255.0f green:green / 255.0f blue:blue / 255.0f alpha:alpha / 255.0f]; +} + + @end diff --git a/ios/mop.podspec b/ios/mop.podspec index db40fbd..b4819ee 100644 --- a/ios/mop.podspec +++ b/ios/mop.podspec @@ -17,10 +17,7 @@ A finclip miniprogram flutter sdk. s.dependency 'Flutter' s.ios.deployment_target = '9.0' - s.dependency 'FinApplet' , '2.35.0-alpha20211231v04' - s.dependency 'FinAppletExt' , '2.35.0-alpha20211231v04' - s.dependency 'FinAppletGDMap' , '2.35.0-alpha20211231v04' - s.dependency 'FinAppletWebRTC' , '2.35.0-alpha20211231v04' - + s.dependency 'FinApplet' , '2.35.1' + s.dependency 'FinAppletExt' , '2.35.1' end diff --git a/lib/api.dart b/lib/api.dart index f849c71..7d29f4e 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -1,5 +1,3 @@ -import 'dart:typed_data'; - class CustomMenu { String menuId; String image; @@ -8,8 +6,7 @@ class CustomMenu { CustomMenu(this.menuId, this.image, this.title, this.type); - Map toJson() => - {'menuId': menuId, 'image': image, 'title': title, 'type': type}; + Map toJson() => {'menuId': menuId, 'image': image, 'title': title, 'type': type}; } abstract class AppletHandler { diff --git a/lib/mop.dart b/lib/mop.dart index 2dd8e92..af3f1b1 100644 --- a/lib/mop.dart +++ b/lib/mop.dart @@ -1,5 +1,7 @@ import 'dart:async'; +import 'dart:ffi'; +import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'package:mop/api.dart'; @@ -8,27 +10,244 @@ typedef MopEventErrorCallback = void Function(dynamic event); typedef ExtensionApiHandler = Future Function(dynamic params); +class FinStoreConfig { + ///创建应用时生成的SDK Key + String sdkKey; + + ///创建应用时生成的SDK secret + String sdkSecret; + + ///服务器地址,客户部署的后台地址 + String apiServer; + + ///apm统计服务器的地址,如果不填,则默认与apiServer一致 + String apmServer; + + ///网络接口加密类型,默认为MD5 国密SM + String cryptType; + + ///SDK指纹 证联环境(https://open.fdep.cn/) 时必填,其他环境的不用填 + String? fingerprint; + + ///是否需要接口加密验证(初始化多服务器时使用)默认为不开启,当设置为YES时开启,接口返回加密数据并处理 + bool encryptServerData; + + FinStoreConfig(this.sdkKey, this.sdkSecret, this.apiServer, this.apmServer, + {this.cryptType = "MD5", + this.fingerprint, + this.encryptServerData = false}); + + Map toMap() { + return { + "sdkKey": sdkKey, + "sdkSecret": sdkSecret, + "apiServer": apiServer, + "apmServer": apmServer, + "cryptType": cryptType, + "fingerprint": fingerprint, + "encryptServerData": encryptServerData + }; + } +} + +class UIConfig { + Map? navigationTitleTextAttributes; //导航栏的标题样式,目前支持了font + + ///当导航栏为默认导航栏时,是否始终显示返回按钮 + bool isAlwaysShowBackInDefaultNavigationBar = false; + + ///是否清除导航栏导航按钮的背景 + bool isClearNavigationBarNavButtonBackground = false; + + ///是否隐藏"更多"菜单中的"反馈与投诉"菜单入口 + bool isHideFeedbackAndComplaints = false; + + ///是否隐藏"更多"菜单中的"返回首页"菜单入口 + bool isHideBackHome = false; + + ///是否隐藏"更多"菜单中的"转发"按钮 + bool isHideForwardMenu = false; + + /// 加载小程序过程中(小程序Service层还未加载成功,基础库还没有向SDK传递小程序配置信息),是否隐藏导航栏的关闭按钮 + bool hideTransitionCloseButton = false; + + /// 禁用侧滑关闭小程序手势 + bool disableSlideCloseAppletGesture = false; + + /// 胶囊按钮配置 + CapsuleConfig? capsuleConfig; + + FloatWindowConfig? floatWindowConfig; + + //iOS中独有的设置属性 + //小程序里加载H5页面时进度条的颜色 格式 0xFFFFAA00 + int? progressBarColor; + //是否自适应暗黑模式。如果设置为true,则更多页面、关于等原生页面会随着手机切换暗黑,也自动调整为暗黑模式 + bool autoAdaptDarkMode = true; + //注入小程序统称appletText字符串,默认为“小程序”。 + String? appletText; + + Map toMap() { + return { + "navigationTitleTextAttributes": navigationTitleTextAttributes, + "isAlwaysShowBackInDefaultNavigationBar": + isAlwaysShowBackInDefaultNavigationBar, + "isClearNavigationBarNavButtonBackground": + isClearNavigationBarNavButtonBackground, + "isHideFeedbackAndComplaints": isHideFeedbackAndComplaints, + "isHideBackHome": isHideBackHome, + "isHideForwardMenu": isHideForwardMenu, + "hideTransitionCloseButton": hideTransitionCloseButton, + "disableSlideCloseAppletGesture": disableSlideCloseAppletGesture, + "capsuleConfig": capsuleConfig?.toMap(), + "floatWindowConfig": floatWindowConfig?.toMap(), + "progressBarColor": progressBarColor, + "autoAdaptDarkMode": autoAdaptDarkMode, + "appletText": appletText + }; + } +} + +/// 胶囊按钮配置 +class CapsuleConfig { + /// 上角胶囊视图的宽度,默认值为88 + double capsuleWidth = 88; + + ///上角胶囊视图的高度,默认值为32 + double capsuleHeight = 32; + + ///右上角胶囊视图的右边距 + double capsuleRightMargin = 7; + + ///右上角胶囊视图的圆角半径,默认值为5 + double capsuleCornerRadius = 5; + + ///右上角胶囊视图的边框宽度,默认值为0.8 + double capsuleBorderWidth = 1; + + ///胶囊背景颜色浅色 + int capsuleBgLightColor = 0x33000000; + + ///胶囊背景颜色深色 + int capsuleBgDarkColor = 0x80ffffff; + + /// 右上角胶囊视图的边框浅色颜色 + + int capsuleBorderLightColor = 0x80ffffff; + + ///右上角胶囊视图的边框深色颜色 + + int capsuleBorderDarkColor = 0x26000000; + + ///胶囊分割线浅色颜色 + int capsuleDividerLightColor = 0x80ffffff; + + ///胶囊分割线深色颜色 + int capsuleDividerDarkColor = 0x26000000; + + ///胶囊里的浅色更多按钮的图片对象,如果不传,会使用默认图标 + int? moreLightImage; + + ///胶囊里的深色更多按钮的图片对象,如果不传,会使用默认图标 + int? moreDarkImage; + + ///胶囊里的更多按钮的宽度,高度与宽度相等 + double moreBtnWidth = 32; + + ///胶囊里的更多按钮的左边距 + double moreBtnLeftMargin = 6; + + ///胶囊里的浅色更多按钮的图片对象,如果不传,会使用默认图标 + + int? closeLightImage; + + ///胶囊里的深色更多按钮的图片对象,如果不传,会使用默认图标 + int? closeDarkImage; + + ///胶囊里的关闭按钮的宽度,高度与宽度相等 + double closeBtnWidth = 32; + + ///胶囊里的关闭按钮的左边距 + double closeBtnLeftMargin = 6; + + Map toMap() { + return { + "capsuleWidth": capsuleWidth, + "capsuleHeight": capsuleHeight, + "capsuleRightMargin": capsuleRightMargin, + "capsuleCornerRadius": capsuleCornerRadius, + "capsuleBorderWidth": capsuleBorderWidth, + "capsuleBgLightColor": capsuleBgLightColor, + "capsuleBgDarkColor": capsuleBgDarkColor, + "capsuleBorderLightColor": capsuleBorderLightColor, + "capsuleBorderDarkColor": capsuleBorderDarkColor, + "capsuleDividerLightColor": capsuleDividerLightColor, + "capsuleDividerDarkColor": capsuleDividerDarkColor, + "moreLightImage": moreLightImage, + "moreDarkImage": moreDarkImage, + "moreBtnWidth": moreBtnWidth, + "moreBtnLeftMargin": moreBtnLeftMargin, + "closeLightImage": closeLightImage, + "closeDarkImage": closeDarkImage, + "closeBtnWidth": closeBtnWidth, + "closeBtnLeftMargin": closeBtnLeftMargin, + }; + } +} + +class FloatWindowConfig { + bool floatMode = false; + int x; + int y; + int width; + int height; + + FloatWindowConfig(this.floatMode, this.x, this.y, this.width, this.height); + + Map toMap() { + return { + "floatMode": floatMode, + "x": x, + "y": y, + "width": width, + "height": height + }; + } +} + +enum Anim { + SlideFromLeftToRightAnim, + SlideFromRightToLeftAnim, + SlideFromTopToBottomAnim, + SlideFromBottomToTopAnim, + FadeInAnim, + NoneAnim +} + class Mop { static final Mop _instance = new Mop._internal(); - MethodChannel _channel; - EventChannel _mopEventChannel; - int eventId = 0; - List> _mopEventQueye = >[]; + late MethodChannel _channel; + late EventChannel _mopEventChannel; + late int eventId = 0; + final List> _mopEventQueye = >[]; - Map _extensionApis = {}; + final Map _extensionApis = {}; + + Map _webExtensionApis = {}; factory Mop() { return _instance; } Mop._internal() { - print('mop: _internal'); + debugPrint('mop: _internal'); // init - _channel = new MethodChannel('mop'); + _channel = const MethodChannel('mop'); _channel.setMethodCallHandler(_handlePlatformMethodCall); - _mopEventChannel = new EventChannel('plugins.mop.finogeeks.com/mop_event'); + _mopEventChannel = + const EventChannel('plugins.mop.finogeeks.com/mop_event'); _mopEventChannel.receiveBroadcastStream().listen((dynamic value) { - print('matrix: receiveBroadcastStream $value'); + debugPrint('matrix: receiveBroadcastStream $value'); for (Map m in _mopEventQueye) { if (m['event'] == value['event']) { m['MopEventCallback'](value['body']); @@ -47,47 +266,77 @@ class Mop { } Future _handlePlatformMethodCall(MethodCall call) async { - print("_handlePlatformMethodCall: method:${call.method}"); + debugPrint("_handlePlatformMethodCall: method:${call.method}"); if (call.method.startsWith("extensionApi:")) { final name = call.method.substring("extensionApi:".length); final handler = _extensionApis[name]; if (handler != null) { return await handler(call.arguments); } - } else if (call.method.startsWith("extensionApi:")) {} + } else if (call.method.startsWith("webExtentionApi:")) { + final name = call.method.substring("webExtentionApi:".length); + final handler = _webExtensionApis[name]; + if (handler != null) { + return await handler(call.arguments); + } + } } /// /// /// initialize mop miniprogram engine. /// 初始化小程序 - /// [appkey] is required. it can be getted from api.finclip.com + /// [sdkkey] is required. it can be getted from api.finclip.com /// [secret] is required. it can be getted from api.finclip.com /// [apiServer] is optional. the mop server address. default is https://mp.finogeek.com /// [apiPrefix] is optional. the mop server prefix. default is /api/v1/mop /// [cryptType] is optional. cryptType, should be MD5/SM /// [disablePermission] is optional. + /// [encryptServerData] 是否对服务器数据进行加密,需要服务器支持 + /// [userId] 用户id + /// [finStoreConfigs] 多服务配置 + /// [uiConfig] UI配置 + /// [debug] 设置debug模式,影响调试和日志 + /// [customWebViewUserAgent] 设置自定义webview ua + /// [appletIntervalUpdateLimit] 设置小程序批量更新周期 + /// [maxRunningApplet] 设置最大同时运行小程序个数 /// - Future initialize(String appkey, String secret, - {String apiServer, - String apiPrefix, - String cryptType, - bool disablePermission, - String userId, - bool encryptServerData = false, - bool debug = false, - bool bindAppletWithMainProcess = false}) async { + Future initialize( + String sdkkey, + String secret, { + String? apiServer, + String? apiPrefix, + String? cryptType, + bool encryptServerData = false, + bool disablePermission = false, + String? userId, + bool debug = false, + bool bindAppletWithMainProcess = false, + List? finStoreConfigs, + UIConfig? uiConfig, + String? customWebViewUserAgent, + int? appletIntervalUpdateLimit, + int? maxRunningApplet, + }) async { + List>? storeConfigs = + finStoreConfigs?.map((e) => e.toMap()).toList(); + final Map ret = await _channel.invokeMethod('initialize', { - 'appkey': appkey, + 'appkey': sdkkey, 'secret': secret, 'apiServer': apiServer, 'apiPrefix': apiPrefix, 'cryptType': cryptType, + "encryptServerData": encryptServerData, 'disablePermission': disablePermission, 'userId': userId, - "encryptServerData": encryptServerData, "debug": debug, - "bindAppletWithMainProcess": bindAppletWithMainProcess + "bindAppletWithMainProcess": bindAppletWithMainProcess, + "finStoreConfigs": storeConfigs, + "uiConfig": uiConfig?.toMap(), + "customWebViewUserAgent": customWebViewUserAgent, + "appletIntervalUpdateLimit": appletIntervalUpdateLimit, + "maxRunningApplet": maxRunningApplet }); return ret; } @@ -104,14 +353,11 @@ class Mop { /// [cryptType] is optional. cryptType, should be MD5/SM Future openApplet( final String appId, { - final String path, - final String query, - final int sequence, - final String apiServer, - final String apiPrefix, - final String fingerprint, - final String cryptType, - final String scene, + final String? path, + final String? query, + final int? sequence, + final String? apiServer, + final String? scene, }) async { Map params = {'appId': appId}; Map param = {}; @@ -120,9 +366,6 @@ class Mop { if (param.length > 0) params["params"] = param; if (sequence != null) params["sequence"] = sequence; if (apiServer != null) params["apiServer"] = apiServer; - if (apiPrefix != null) params["apiPrefix"] = apiPrefix; - if (fingerprint != null) params["fingerprint"] = fingerprint; - if (cryptType != null) params["cryptType"] = cryptType; if (scene != null) param["scene"] = scene; final Map ret = await _channel.invokeMethod('openApplet', params); return ret; @@ -136,7 +379,7 @@ class Mop { /// Future> currentApplet() async { final ret = await _channel.invokeMapMethod("currentApplet"); - return Map.from(ret); + return Map.from(ret!); } /// @@ -167,7 +410,7 @@ class Mop { Future sdkVersion() async { return await _channel .invokeMapMethod("sdkVersion") - .then((value) => value["data"]); + .then((value) => value?["data"]); } /// @@ -190,7 +433,7 @@ class Mop { String qrCode, String apiServer) async { final ret = await _channel.invokeMapMethod("parseAppletInfoFromWXQrCode", {"qrCode": qrCode, "apiServer": apiServer}); - return Map.from(ret); + return Map.from(ret!); } /// @@ -207,7 +450,7 @@ class Mop { _extensionApis["getCustomMenus"] = (params) async { final res = await handler.getCustomMenus(params["appId"]); List> list = []; - res?.forEach((element) { + res.forEach((element) { Map map = Map(); map["menuId"] = element.menuId; map["image"] = element.image; @@ -215,7 +458,7 @@ class Mop { map["type"] = element.type; list.add(map); }); - print("registerAppletHandler getCustomMenus list $list"); + debugPrint("registerAppletHandler getCustomMenus list $list"); return list; }; _extensionApis["onCustomMenuClick"] = (params) async { @@ -241,8 +484,8 @@ class Mop { Future getSMSign(String plainText) async { var result = await _channel.invokeMapMethod("smsign", {'plainText': plainText}); - var data = result['data']['data']; - print(data); + var data = result?['data']['data']; + debugPrint(data); return data; } @@ -251,4 +494,51 @@ class Mop { await _channel.invokeMapMethod("webViewBounces", {'bounces': bounces}); return; } + + //关闭小程序 小程序会在内存中存在 + Future closeApplet(String appletId, bool animated) async { + await _channel.invokeMethod( + "closeApplet", {"appletId": appletId, "animated": animated}); + return; + } + + //结束小程序 小程序会从内存中清除 + Future finishRunningApplet(String appletId, bool animated) async { + await _channel.invokeMethod( + "finishRunningApplet", {"appletId": appletId, "animated": animated}); + return; + } + + //设置小程序切换动画 安卓 + Future setActivityTransitionAnim(Anim anim) async { + await _channel + .invokeMethod("setActivityTransitionAnim", {"anim": anim.name}); + return; + } + + //发送事件给小程序 + Future sendCustomEvent( + String appId, Map eventData) async { + await _channel.invokeMethod( + "sendCustomEvent", {"appId": appId, "eventData": eventData}); + return; + } + + //原生调用js + Future callJS(String appId, String eventName, String nativeViewId, + Map eventData) async { + await _channel.invokeMethod("callJS", { + "appId": appId, + "eventName": eventName, + "nativeViewId": nativeViewId, + "eventData": eventData + }); + return; + } + + //注册h5的拓展接口 + void addWebExtentionApi(String name, ExtensionApiHandler handler) { + _webExtensionApis[name] = handler; + _channel.invokeMethod("addWebExtentionApi", {"name": name}); + } } diff --git a/pubspec.lock b/pubspec.lock index 65b1ee6..ca3bc9d 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -7,7 +7,7 @@ packages: name: async url: "https://pub.flutter-io.cn" source: hosted - version: "2.6.1" + version: "2.8.2" boolean_selector: dependency: transitive description: @@ -21,14 +21,14 @@ packages: name: characters url: "https://pub.flutter-io.cn" source: hosted - version: "1.1.0" + version: "1.2.0" charcode: dependency: transitive description: name: charcode url: "https://pub.flutter-io.cn" source: hosted - version: "1.2.0" + version: "1.3.1" clock: dependency: transitive description: @@ -55,25 +55,46 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.4" + flutter_plugin_android_lifecycle: + dependency: "direct main" + description: + name: flutter_plugin_android_lifecycle + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.5" flutter_test: dependency: "direct dev" description: flutter source: sdk version: "0.0.0" + lints: + dependency: transitive + description: + name: lints + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.1" matcher: dependency: transitive description: name: matcher url: "https://pub.flutter-io.cn" source: hosted - version: "0.12.10" + version: "0.12.11" meta: dependency: transitive description: name: meta url: "https://pub.flutter-io.cn" source: hosted - version: "1.3.0" + version: "1.7.0" path: dependency: transitive description: @@ -127,7 +148,7 @@ packages: name: test_api url: "https://pub.flutter-io.cn" source: hosted - version: "0.3.0" + version: "0.4.3" typed_data: dependency: transitive description: @@ -141,7 +162,7 @@ packages: name: vector_math url: "https://pub.flutter-io.cn" source: hosted - version: "2.1.0" + version: "2.1.1" sdks: - dart: ">=2.12.0 <3.0.0" - flutter: ">=1.10.0" + dart: ">=2.14.0 <3.0.0" + flutter: ">=2.2.3" diff --git a/pubspec.tpl.yaml b/pubspec.tpl.yaml index b950490..1fda902 100644 --- a/pubspec.tpl.yaml +++ b/pubspec.tpl.yaml @@ -4,16 +4,18 @@ version: '__mop_flutter_sdk_version__' homepage: https://github.com/finogeeks/mop-flutter-sdk environment: - sdk: '>=2.1.0 <3.0.0' - flutter: '^1.10.0' + sdk: '>=2.12.0 <3.0.0' + flutter: '^2.2.3' dependencies: flutter: sdk: flutter + flutter_plugin_android_lifecycle: ^2.0.3 dev_dependencies: flutter_test: sdk: flutter + flutter_lints: ^1.0.0 flutter: plugin: diff --git a/pubspec.yaml b/pubspec.yaml index 5b1e732..0133d19 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,19 +1,21 @@ name: mop description: A Finogeeks MiniProgram Flutter SDK. -version: '2.34.12' +version: '2.35.1' homepage: https://github.com/finogeeks/mop-flutter-sdk environment: - sdk: '>=2.1.0 <3.0.0' - flutter: '^1.10.0' + sdk: '>=2.12.0 <3.0.0' + flutter: '^2.2.3' dependencies: flutter: sdk: flutter + flutter_plugin_android_lifecycle: ^2.0.3 dev_dependencies: flutter_test: sdk: flutter + flutter_lints: ^1.0.0 flutter: plugin: diff --git a/test/mop_test.dart b/test/mop_test.dart index 772816b..2f12533 100644 --- a/test/mop_test.dart +++ b/test/mop_test.dart @@ -5,6 +5,8 @@ import 'package:mop/mop.dart'; void main() { const MethodChannel channel = MethodChannel('mop'); + TestWidgetsFlutterBinding.ensureInitialized(); + setUp(() { channel.setMockMethodCallHandler((MethodCall methodCall) async { return '42';