├── .github └── workflows │ └── publish.yml ├── .gitignore ├── .idea ├── libraries │ └── Flutter_for_Android.xml ├── modules.xml └── runConfigurations │ └── example_lib_main_dart.xml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── android ├── .gitignore ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── com │ └── jiguang │ └── jmessageflutter │ ├── ChatRoomHandler.java │ ├── JMessageUtils.java │ ├── JmessageFlutterPlugin.java │ ├── JsonUtils.java │ └── PushService.java ├── documents └── APIs.md ├── example ├── .flutter-plugins-dependencies ├── .gitignore ├── .metadata ├── README.md ├── android │ ├── app │ │ ├── build.gradle │ │ └── src │ │ │ └── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── java │ │ │ └── com │ │ │ │ └── jiguang │ │ │ │ └── jmessageflutterexample │ │ │ │ └── MainActivity.java │ │ │ └── res │ │ │ ├── drawable │ │ │ └── launch_background.xml │ │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── values-night │ │ │ └── styles.xml │ │ │ └── values │ │ │ └── styles.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ └── gradle-wrapper.properties │ ├── key.properties │ └── settings.gradle ├── assets │ ├── 2.0x │ │ └── nav_close.png │ ├── 3.0x │ │ └── nav_close.png │ └── nav_close.png ├── ios │ ├── Flutter │ │ ├── .last_build_id │ │ ├── AppFrameworkInfo.plist │ │ ├── Debug.xcconfig │ │ ├── Flutter.podspec │ │ ├── Release.xcconfig │ │ └── flutter_export_environment.sh │ ├── Podfile │ ├── Runner.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ └── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── Runner.xcscheme │ ├── Runner.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ └── Runner │ │ ├── AppDelegate.h │ │ ├── AppDelegate.m │ │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ ├── Icon-App-20x20@1x.png │ │ │ ├── Icon-App-20x20@2x.png │ │ │ ├── Icon-App-20x20@3x.png │ │ │ ├── Icon-App-29x29@1x.png │ │ │ ├── Icon-App-29x29@2x.png │ │ │ ├── Icon-App-29x29@3x.png │ │ │ ├── Icon-App-40x40@1x.png │ │ │ ├── Icon-App-40x40@2x.png │ │ │ ├── Icon-App-40x40@3x.png │ │ │ ├── Icon-App-60x60@2x.png │ │ │ ├── Icon-App-60x60@3x.png │ │ │ ├── Icon-App-76x76@1x.png │ │ │ ├── Icon-App-76x76@2x.png │ │ │ └── Icon-App-83.5x83.5@2x.png │ │ └── LaunchImage.imageset │ │ │ ├── Contents.json │ │ │ ├── LaunchImage.png │ │ │ ├── LaunchImage@2x.png │ │ │ ├── LaunchImage@3x.png │ │ │ └── README.md │ │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ │ ├── Info.plist │ │ ├── Runner.entitlements │ │ └── main.m ├── lib │ ├── conversation_manage_view.dart │ ├── group_manage_view.dart │ └── main.dart └── pubspec.yaml ├── ios ├── .gitignore ├── Assets │ └── .gitkeep ├── Classes │ ├── JMessageHelper.h │ ├── JMessageHelper.m │ ├── JmessageFlutterPlugin.h │ └── JmessageFlutterPlugin.m └── jmessage_flutter.podspec ├── jmessage_flutter.iml ├── jmessage_flutter_android.iml ├── lib └── jmessage_flutter.dart └── pubspec.yaml /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: publish 2 | 3 | on: 4 | push: 5 | tags: 6 | - v* 7 | 8 | jobs: 9 | build: 10 | 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v2 15 | 16 | - name: Publish Dart/Flutter package 17 | uses: sakebook/actions-flutter-pub-publisher@v1.3.1 18 | with: 19 | credential: ${{ secrets.JMESSAGE_CREDENTIAL_JSON }} 20 | flutter_package: false 21 | skip_test: true 22 | dry_run: false 23 | 24 | 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .dart_tool/ 3 | 4 | .packages 5 | .pub/ 6 | pubspec.lock 7 | 8 | build/ 9 | .idea/ 10 | flutter.jar 11 | example/.flutter-plugins-dependencies 12 | jmessage_flutter_android.iml 13 | example/ios/Flutter/flutter_export_environment.sh -------------------------------------------------------------------------------- /.idea/libraries/Flutter_for_Android.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/runConfigurations/example_lib_main_dart.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 2.2.1 2 | +修复  addSyncRoamingMessageListener 没回调问题 3 | ## 2.2.0 4 | +修复  enterChatRoom getChatRoomConversation 方法 5 | ## 2.1.9 6 | +补充  nicknames 字段 7 | ## 2.1.8 8 | +新增  nicknames 字段 9 | ## 2.1.7 10 | +修复:修复未实现方法getMessageHaveReadStatus 11 | ## 2.1.6 12 | +修复:修复判空异常 13 | ## 2.1.4 14 | +新增:新增发送视频接口 sendVideoMessage 15 | ## 2.1.2 16 | +升级:升级 android jcore 2.8.2 17 | ## 2.1.0 18 | +适配:适配 null safety 19 | ## 2.0.5 20 | + 升级:Android jcore sdk 升级到 2.7.8 21 | ## 2.0.3 22 | + 升级:Android msg sdk 升级到 2.1.4 23 | ## 2.0.1 24 | + 适配Flutter 2.0 25 | ## 0.6.5 26 | + 修复Android端下载消息原图失败问题 27 | ## 0.6.4 28 | + 聊天室消息添加监听、移除监听方法修改 29 | + 修复聊天室消息移除监听失败问题 30 | ## 0.6.3 31 | + 新增:消息已读回执监听方法 32 | ## 0.6.2 33 | + 内部安全策略优化 34 | ## 0.6.1 35 | + 修复:获取用户信息时黑名单字段错误问题 36 | ## 0.6.0 37 | + 修复:获取消息失败问题 38 | + 注意:接口参数请严格按照接口说明传值 39 | ## 0.5.0 40 | + 修复:黑名单接口异常 41 | ## 0.4.0 42 | + 1、新增:消息已读未读回执功能 43 | + 2、修复:删除会话 Android 报错问题 44 | + 3、下载消息多媒体文件时,统一传入本地消息 id 45 | + 4、统一iOS、Android 的用户登录状态变更事件枚举 46 | ## 0.3.0 47 | ### fix: 48 | + 1、新增:发送消息透传接口,支持会话间、设备间透传命令; 49 | + 2、修复经纬度数据错误问题; 50 | ## 0.2.0 51 | fix: 52 | 1、新增:消息撤回类型消息; 53 | 2、修复:Group 和 GroupInfo 属性 maxMemberCount 改为 int 类型; 54 | 3、修复:获取我的群组 crash 55 | 56 | ## 0.1.0 57 | fix: 58 | 1、修复:createMessage 方法中经纬度为 int 的错误; 59 | 2、修复:在 Android 下 GroupInfo 的属性 maxMemberCount 为 int 的错误; 60 | 3、修复:消息撤回事件回调中 message 为 null 的错误; 61 | 4、修复:监听不到入群申请通知事件的 bug ; 62 | ## 0.0.20 63 | fix: 64 | 1、修改: sendLocationMessage 方法经纬度参数改为 double 类型 65 | ## 0.0.19 66 | fix: 67 | 1、修复:Android 接收消息时 flutter 没回调问题 68 | 2、适配 Android 最新 SDK 69 | 3、修改代码书写错误 70 | ## 0.0.18 71 | fix: 72 | 1、添加 iOS 端 apns 注册方法 73 | 2、修复:Android 端 serverMessageId 超过 int 存储范围问题; 74 | 3、更新到最新版本 JMessage SDK 75 | ## 0.0.17 76 | fix: 77 | 1、修复IOS发送文件消息获取不到文件问题 78 | ## 0.0.16 79 | fix: 80 | 1、修复发送自定义消息解析失败的bug 81 | 2、修复安卓端exitConversation没有回调的问题。 82 | 3、升级安卓端JMessage sdk版本2.8.2 83 | 84 | ## 0.0.15 85 | fix: 86 | 1.修复getHistoryMessages 安卓和ios的消息排序不一致 87 | 2.修复updateMyInfo 的参数缺失问题。 88 | ## 0.0.14 89 | fix: contact event username is null bug 90 | 91 | ## 0.0.13 92 | feature: getHistoryMessages parameters add isDescend-option. 93 | 94 | ## 0.0.12 95 | feature: onLoginStateChanged add user_kicked event. 96 | 97 | ## 0.0.11 98 | fix: jmessage login api remove without avatar path error. 99 | 100 | ## 0.0.10 101 | fix: updateGroupInfo update desc error. 102 | new feature: add extras field in JMConversationInfo. 103 | 104 | ## 0.0.9 105 | 106 | fix: JMConversationInfo getHistoryMessages helper function 107 | 108 | ## 0.0.8 109 | 110 | fix: group.maxMemberCount type 111 | 112 | ## 0.0.7 113 | 114 | new feature: add message.state property 115 | 116 | ## 0.0.6 117 | 118 | fix: voice message error 119 | new feature: add createMessage and sendMessage api 120 | 121 | ## 0.0.5 122 | 123 | fix: login state changed not fire in android 124 | 125 | ## 0.0.4 126 | 127 | fix:isSend 返回 null 的情况。 128 | 129 | ## 0.0.3 130 | 131 | fix:android isSend 返回错误。 132 | 133 | ## 0.0.2 134 | 135 | fix:swift 工程集成报错。 136 | 137 | ## 0.0.1 138 | 139 | 第一个版本。 140 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 极光开发者 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![QQ Group](https://img.shields.io/badge/QQ%20Group-862401307-red.svg)]() 2 | [![pub package](https://img.shields.io/pub/v/jmessage_flutter.svg)](https://pub.flutter-io.cn/packages/jmessage_flutter) 3 | 4 | # jmessage_flutter 5 | 6 | ### 安装 7 | 8 | 在工程 pubspec.yaml 中加入 dependencies 9 | 10 | ``` 11 | //github 集成 12 | dependencies: 13 | jmessage_flutter: 14 | git: 15 | url: git://github.com/jpush/jmessage-flutter-plugin.git 16 | ref: master 17 | 18 | //pub.dev 集成 19 | dependencies: 20 | jmessage_flutter: 2.2.1 21 | ``` 22 | 23 | 24 | ### 配置 25 | 26 | 在 `/android/app/build.gradle` 中添加下列代码: 27 | 28 | ```gradle 29 | android { 30 | ...... 31 | defaultConfig { 32 | applicationId "com.xxx.xxx" //JPush上注册的包名. 33 | ...... 34 | 35 | ndk { 36 | //选择要添加的对应cpu类型的.so库。 37 | abiFilters 'armeabi', 'armeabi-v7a', 'armeabi-v8a' 38 | // 还可以添加 'x86', 'x86_64', 'mips', 'mips64' 39 | } 40 | 41 | manifestPlaceholders = [ 42 | JPUSH_PKGNAME : applicationId, 43 | JPUSH_APPKEY : "你的appkey", //JPush上注册的包名对应的appkey. 44 | JPUSH_CHANNEL : "developer-default", //暂时填写默认值即可. 45 | ] 46 | ...... 47 | } 48 | ...... 49 | } 50 | ``` 51 | 52 | 53 | 54 | ### 使用 55 | 56 | ```dart 57 | import 'package:jmessage_flutter/jmessage_flutter.dart'; 58 | ``` 59 | 60 | 61 | 62 | ### APIs 63 | 64 | **注意** : 需要先调用 `JmessageFlutter().init` 来初始化插件,才能保证其它功能正常工作。 65 | 66 | [参考](/documents/APIs.md) 67 | 68 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | group 'com.jiguang.jmessageflutter' 2 | version '1.0-SNAPSHOT' 3 | 4 | buildscript { 5 | repositories { 6 | mavenCentral() 7 | google() 8 | jcenter() 9 | } 10 | 11 | dependencies { 12 | classpath 'com.android.tools.build:gradle:3.2.1' 13 | } 14 | } 15 | 16 | rootProject.allprojects { 17 | repositories { 18 | mavenCentral() 19 | google() 20 | jcenter() 21 | } 22 | } 23 | 24 | apply plugin: 'com.android.library' 25 | 26 | android { 27 | compileSdkVersion 28 28 | 29 | defaultConfig { 30 | minSdkVersion 17 31 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 32 | 33 | } 34 | lintOptions { 35 | disable 'InvalidPackage' 36 | } 37 | } 38 | 39 | dependencies { 40 | implementation 'cn.jiguang.sdk:jmessage:2.9.2' 41 | implementation 'cn.jiguang.sdk:jcore:2.8.2' 42 | } -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpush/jmessage-flutter-plugin/f19f8a0f7f1068362a0098314b22a1d6883ff2a5/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Apr 02 18:21:36 CST 2019 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip 7 | -------------------------------------------------------------------------------- /android/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'jmessage_flutter' 2 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /android/src/main/java/com/jiguang/jmessageflutter/ChatRoomHandler.java: -------------------------------------------------------------------------------- 1 | package com.jiguang.jmessageflutter; 2 | 3 | //import org.apache.cordova.CallbackContext; 4 | import org.json.JSONArray; 5 | import org.json.JSONException; 6 | import org.json.JSONObject; 7 | 8 | import java.util.ArrayList; 9 | import java.util.HashMap; 10 | import java.util.HashSet; 11 | import java.util.List; 12 | import java.util.Set; 13 | 14 | import cn.jpush.im.android.api.ChatRoomManager; 15 | import cn.jpush.im.android.api.JMessageClient; 16 | import cn.jpush.im.android.api.callback.RequestCallback; 17 | import cn.jpush.im.android.api.model.ChatRoomInfo; 18 | import cn.jpush.im.android.api.model.Conversation; 19 | import cn.jpush.im.api.BasicCallback; 20 | 21 | import static com.jiguang.jmessageflutter.JmessageFlutterPlugin.ERR_CODE_PARAMETER; 22 | import static com.jiguang.jmessageflutter.JmessageFlutterPlugin.ERR_MSG_PARAMETER; 23 | import static com.jiguang.jmessageflutter.JMessageUtils.handleResult; 24 | import static com.jiguang.jmessageflutter.JsonUtils.toJson; 25 | 26 | import io.flutter.plugin.common.MethodChannel.Result; 27 | 28 | 29 | /** 30 | * 处理聊天室相关 API。 31 | */ 32 | 33 | class ChatRoomHandler { 34 | 35 | static void getChatRoomInfoListOfApp(JSONObject data, final Result callback) { 36 | int start, count; 37 | try { 38 | 39 | start = data.getInt("start"); 40 | count = data.getInt("count"); 41 | } catch (JSONException e) { 42 | e.printStackTrace(); 43 | handleResult(ERR_CODE_PARAMETER, ERR_MSG_PARAMETER, callback); 44 | return; 45 | } 46 | 47 | ChatRoomManager.getChatRoomListByApp(start, count, new RequestCallback>() { 48 | @Override 49 | public void gotResult(int status, String desc, List chatRoomInfos) { 50 | if (status != 0) { 51 | handleResult(status, desc, callback); 52 | return; 53 | } 54 | 55 | ArrayList jsonArr = new ArrayList(); 56 | for (ChatRoomInfo chatroomInfo : chatRoomInfos) { 57 | jsonArr.add(toJson(chatroomInfo)); 58 | } 59 | callback.success(jsonArr); 60 | } 61 | }); 62 | } 63 | 64 | static void getChatRoomInfoListOfUser(JSONObject data, final Result callback) { 65 | ChatRoomManager.getChatRoomListByUser(new RequestCallback>() { 66 | @Override 67 | public void gotResult(int status, String desc, List chatRoomInfoList) { 68 | if (status != 0) { 69 | handleResult(status, desc, callback); 70 | return; 71 | } 72 | 73 | ArrayList jsonArr = new ArrayList(); 74 | for (ChatRoomInfo chatroomInfo : chatRoomInfoList) { 75 | jsonArr.add(toJson(chatroomInfo)); 76 | } 77 | callback.success(jsonArr); 78 | } 79 | }); 80 | } 81 | 82 | static void getChatRoomInfoListById(JSONObject data, final Result callback) { 83 | Set roomIds = new HashSet(); // JS 层为了和 iOS 统一,因此 roomId 类型为 String,在原生做转换。 84 | 85 | try { 86 | 87 | JSONArray roomIdArr = data.getJSONArray("roomIds"); 88 | 89 | for (int i = 0; i < roomIdArr.length(); i++) { 90 | roomIds.add(Long.valueOf(roomIdArr.getString(i))); 91 | } 92 | } catch (JSONException e) { 93 | e.printStackTrace(); 94 | handleResult(ERR_CODE_PARAMETER, ERR_MSG_PARAMETER, callback); 95 | return; 96 | } 97 | 98 | ChatRoomManager.getChatRoomInfos(roomIds, new RequestCallback>() { 99 | @Override 100 | public void gotResult(int status, String desc, List chatRoomInfos) { 101 | if (status != 0) { 102 | handleResult(status, desc, callback); 103 | return; 104 | } 105 | 106 | ArrayList jsonArr = new ArrayList(); 107 | for (ChatRoomInfo chatroomInfo : chatRoomInfos) { 108 | jsonArr.add(toJson(chatroomInfo)); 109 | } 110 | callback.success(jsonArr); 111 | } 112 | }); 113 | } 114 | 115 | static void getChatRoomOwner(JSONObject data, final Result callback) { 116 | final long roomId; 117 | 118 | try { 119 | roomId = Long.parseLong(data.getString("roomId")); 120 | } catch (JSONException e) { 121 | e.printStackTrace(); 122 | handleResult(ERR_CODE_PARAMETER, ERR_MSG_PARAMETER, callback); 123 | return; 124 | } 125 | 126 | Set roomIds = new HashSet(); 127 | roomIds.add(roomId); 128 | 129 | ChatRoomManager.getChatRoomInfos(roomIds, new RequestCallback>() { 130 | @Override 131 | public void gotResult(int status, String desc, List chatRoomInfoList) { 132 | if (status != 0) { 133 | handleResult(status, desc, callback); 134 | return; 135 | } 136 | 137 | HashMap chatroomInfoJson = toJson(chatRoomInfoList.get(0)); 138 | callback.success(chatroomInfoJson); 139 | } 140 | }); 141 | } 142 | 143 | static void enterChatRoom(JSONObject data, final Result callback) { 144 | final long roomId; 145 | 146 | try { 147 | roomId = Long.parseLong(data.getString("roomId")); 148 | } catch (JSONException e) { 149 | e.printStackTrace(); 150 | handleResult(ERR_CODE_PARAMETER, ERR_MSG_PARAMETER, callback); 151 | return; 152 | } 153 | 154 | ChatRoomManager.enterChatRoom(roomId, new RequestCallback() { 155 | @Override 156 | public void gotResult(int status, String desc, Conversation conversation) { 157 | if (status != 0) { 158 | handleResult(status, desc, callback); 159 | return; 160 | } 161 | 162 | // HashMap result = new HashMap(); 163 | // result.put("roomId", roomId); 164 | // result.put("conversation", toJson(conversation)); 165 | callback.success(toJson(conversation)); 166 | } 167 | }); 168 | } 169 | 170 | static void exitChatRoom(JSONObject data, final Result callback) { 171 | final long roomId; 172 | 173 | try { 174 | roomId = Long.parseLong(data.getString("roomId")); 175 | } catch (JSONException e) { 176 | e.printStackTrace(); 177 | handleResult(ERR_CODE_PARAMETER, ERR_MSG_PARAMETER, callback); 178 | return; 179 | } 180 | 181 | ChatRoomManager.leaveChatRoom(roomId, new BasicCallback() { 182 | @Override 183 | public void gotResult(int status, String desc) { 184 | if (status == 0) { // success 185 | callback.success(null); 186 | } else { 187 | handleResult(status, desc, callback); 188 | } 189 | } 190 | }); 191 | } 192 | 193 | static void getChatRoomConversationList(JSONObject data, final Result callback) { 194 | List conversations = JMessageClient.getChatRoomConversationList(); 195 | 196 | ArrayList result = new ArrayList(); 197 | 198 | if (conversations == null) { 199 | callback.success(result); 200 | return; 201 | } 202 | 203 | for (Conversation con : conversations) { 204 | result.add(toJson(con)); 205 | } 206 | callback.success(result); 207 | } 208 | 209 | } 210 | -------------------------------------------------------------------------------- /android/src/main/java/com/jiguang/jmessageflutter/JMessageUtils.java: -------------------------------------------------------------------------------- 1 | package com.jiguang.jmessageflutter; 2 | 3 | import android.graphics.Bitmap; 4 | import android.os.Environment; 5 | import android.util.Log; 6 | 7 | //import org.apache.cordova.CallbackContext; 8 | import org.json.JSONArray; 9 | import org.json.JSONException; 10 | import org.json.JSONObject; 11 | 12 | 13 | import java.io.BufferedOutputStream; 14 | import java.io.File; 15 | import java.io.FileNotFoundException; 16 | import java.io.FileOutputStream; 17 | import java.io.IOException; 18 | import java.net.URI; 19 | import java.util.HashMap; 20 | import java.util.List; 21 | 22 | import cn.jpush.im.android.api.JMessageClient; 23 | import cn.jpush.im.android.api.callback.GetUserInfoCallback; 24 | import cn.jpush.im.android.api.content.MessageContent; 25 | import cn.jpush.im.android.api.model.Conversation; 26 | import cn.jpush.im.android.api.model.Message; 27 | import cn.jpush.im.android.api.options.MessageSendingOptions; 28 | import cn.jpush.im.api.BasicCallback; 29 | 30 | import static com.jiguang.jmessageflutter.JsonUtils.JsonToMessage; 31 | import io.flutter.plugin.common.MethodChannel.Result; 32 | 33 | class JMessageUtils { 34 | 35 | private static JSONObject getErrorObject(int code, String description) throws JSONException { 36 | JSONObject error = new JSONObject(); 37 | error.put("code", code); 38 | error.put("description", description); 39 | return error; 40 | } 41 | 42 | static void handleResult(int status, String desc, Result callback) { 43 | if (status == 0) { 44 | callback.success(null); 45 | } else { 46 | callback.error(Integer.toString(status), desc, ""); 47 | } 48 | } 49 | 50 | static void handleResult(HashMap returnObject, int status, String desc, Result callback) { 51 | if (status == 0) { 52 | callback.success(returnObject); 53 | } else { 54 | callback.error(Integer.toString(status), desc, ""); 55 | } 56 | } 57 | 58 | static void handleResult(List returnObject, int status, String desc, Result callback) { 59 | if (status == 0) { 60 | callback.success(returnObject); 61 | } else { 62 | callback.error(Integer.toString(status), desc, ""); 63 | } 64 | } 65 | 66 | static MessageSendingOptions toMessageSendingOptions(JSONObject json) throws JSONException { 67 | MessageSendingOptions messageSendingOptions = new MessageSendingOptions(); 68 | 69 | if (json.has("isShowNotification") && !json.isNull("isShowNotification")) { 70 | messageSendingOptions.setShowNotification(json.getBoolean("isShowNotification")); 71 | } 72 | 73 | if (json.has("isRetainOffline") && !json.isNull("isRetainOffline")) { 74 | messageSendingOptions.setRetainOffline(json.getBoolean("isRetainOffline")); 75 | } 76 | 77 | if (json.has("isCustomNotificationEnabled") && !json.isNull("isCustomNotificationEnabled")) { 78 | messageSendingOptions.setCustomNotificationEnabled(json.getBoolean("isCustomNotificationEnabled")); 79 | } 80 | 81 | if (json.has("notificationTitle") && !json.isNull("notificationTitle")) { 82 | messageSendingOptions.setNotificationTitle(json.getString("notificationTitle")); 83 | } 84 | 85 | if (json.has("notificationText") && !json.isNull("notificationText")) { 86 | messageSendingOptions.setNotificationText(json.getString("notificationText")); 87 | } 88 | if (json.has("needReadReceipt") && !json.isNull("needReadReceipt")) { 89 | messageSendingOptions.setNeedReadReceipt(json.getBoolean("needReadReceipt")); 90 | } 91 | 92 | return messageSendingOptions; 93 | } 94 | 95 | static void getUserInfo(JSONObject params, GetUserInfoCallback callback) throws JSONException { 96 | String username, appKey; 97 | 98 | username = params.getString("username"); 99 | appKey = params.has("appKey") ? params.getString("appKey") : ""; 100 | 101 | JMessageClient.getUserInfo(username, appKey, callback); 102 | } 103 | 104 | /** 105 | * 创建会话对象,如果本地以及存在,则直接返回而不会重新创建。 106 | */ 107 | static Conversation createConversation(JSONObject params) throws JSONException { 108 | String type = params.getString("type"); 109 | Conversation conversation = null; 110 | 111 | if (type.equals("single")) { 112 | String username = params.getString("username"); 113 | String appKey = params.has("appKey") ? params.getString("appKey") : ""; 114 | conversation = Conversation.createSingleConversation(username, appKey); 115 | 116 | } else if (type.equals("group")) { 117 | String groupId = params.getString("groupId"); 118 | conversation = Conversation.createGroupConversation(Long.parseLong(groupId)); 119 | 120 | } else if (type.equals("chatRoom")) { 121 | long roomId = Long.parseLong(params.getString("roomId")); 122 | conversation = Conversation.createChatRoomConversation(roomId); 123 | } 124 | 125 | return conversation; 126 | } 127 | 128 | static Conversation getConversation(JSONObject params) throws JSONException { 129 | String type = params.getString("type"); 130 | Conversation conversation = null; 131 | 132 | if (type.equals("group")) { 133 | String groupId = params.getString("groupId"); 134 | conversation = JMessageClient.getGroupConversation(Long.parseLong(groupId)); 135 | 136 | } else if (type.equals("chatRoom")) { 137 | long roomId = Long.parseLong(params.getString("roomId")); 138 | conversation = JMessageClient.getChatRoomConversation(roomId); 139 | } else {//if (type.equals("single")) || "user" 140 | String username = params.getString("username"); 141 | String appKey = params.has("appKey") ? params.getString("appKey") : ""; 142 | conversation = JMessageClient.getSingleConversation(username, appKey); 143 | } 144 | 145 | return conversation; 146 | } 147 | 148 | static Message getMessage(JSONObject params) throws JSONException { 149 | if (params.has("messageId")) { // 代表 JS 层为显式传入所需的参数。 150 | Conversation conversation = getConversation(params); 151 | if (conversation == null) { 152 | return null; 153 | } 154 | 155 | Message msg; 156 | String messageId = params.getString("messageId"); 157 | 158 | Long b = Long.parseLong(messageId); 159 | if (b > Integer.MAX_VALUE) { 160 | msg = conversation.getMessage(Long.parseLong(messageId)); 161 | }else { 162 | msg = conversation.getMessage(Integer.parseInt(messageId)); 163 | } 164 | 165 | return msg; 166 | } else if (params.has("id")) { // 代表 JS 层传入的是 Message 对象。 167 | return JsonToMessage(params); 168 | } 169 | 170 | return null; 171 | } 172 | 173 | static void sendMessage(Conversation conversation, MessageContent content, MessageSendingOptions options, 174 | final Result callback) { 175 | final Message msg = conversation.createSendMessage(content); 176 | msg.setOnSendCompleteCallback(new BasicCallback() { 177 | @Override 178 | public void gotResult(int status, String desc) { 179 | if (status == 0) { 180 | HashMap json = JsonUtils.toJson(msg); 181 | handleResult(json, status, desc, callback); 182 | } else { 183 | handleResult(status, desc, callback); 184 | } 185 | } 186 | }); 187 | 188 | if (options == null) { 189 | JMessageClient.sendMessage(msg); 190 | } else { 191 | JMessageClient.sendMessage(msg, options); 192 | } 193 | } 194 | 195 | static String storeImage(Bitmap bitmap, String filename, String pkgName) { 196 | File avatarFile = new File(getAvatarPath(pkgName)); 197 | if (!avatarFile.exists()) { 198 | avatarFile.mkdirs(); 199 | } 200 | 201 | String filePath = getAvatarPath(pkgName) + filename + ".png"; 202 | try { 203 | FileOutputStream fos = new FileOutputStream(filePath); 204 | BufferedOutputStream bos = new BufferedOutputStream(fos); 205 | bitmap.compress(Bitmap.CompressFormat.PNG, 100, bos); 206 | bos.flush(); 207 | bos.close(); 208 | return filePath; 209 | } catch (FileNotFoundException e) { 210 | e.printStackTrace(); 211 | return ""; 212 | } catch (IOException e) { 213 | e.printStackTrace(); 214 | return ""; 215 | } 216 | } 217 | 218 | static String getFilePath(String pkgName) { 219 | return Environment.getExternalStorageDirectory() + "/" + pkgName; 220 | } 221 | 222 | static String getAvatarPath(String pkgName) { 223 | return getFilePath(pkgName) + "/images/avatar/"; 224 | } 225 | 226 | static String getFileExtension(String path) { 227 | return path.substring(path.lastIndexOf(".")); 228 | } 229 | 230 | /** 231 | * 根据绝对路径或 URI 获得本地图片。 232 | * 233 | * @param path 文件路径或者 URI。 234 | * @return 文件对象。 235 | */ 236 | static File getFile(String path) throws FileNotFoundException { 237 | File file = new File(path); // if it is a absolute path 238 | 239 | if (!file.isFile()) { 240 | URI uri = URI.create(path); // if it is a uri. 241 | file = new File(uri); 242 | } 243 | 244 | if (!file.exists() || !file.isFile()) { 245 | throw new FileNotFoundException(); 246 | } 247 | 248 | return file; 249 | } 250 | 251 | } 252 | -------------------------------------------------------------------------------- /android/src/main/java/com/jiguang/jmessageflutter/JsonUtils.java: -------------------------------------------------------------------------------- 1 | package com.jiguang.jmessageflutter; 2 | 3 | import android.text.TextUtils; 4 | import android.util.Log; 5 | 6 | import org.json.JSONArray; 7 | import org.json.JSONException; 8 | import org.json.JSONObject; 9 | 10 | import java.text.DateFormat; 11 | import java.text.SimpleDateFormat; 12 | import java.util.ArrayList; 13 | import java.util.Date; 14 | import java.util.HashMap; 15 | import java.util.Iterator; 16 | import java.util.List; 17 | import java.util.Map; 18 | 19 | import cn.jmessage.support.google.gson.JsonElement; 20 | import cn.jmessage.support.google.gson.JsonObject; 21 | import cn.jmessage.support.google.gson.JsonParser; 22 | import cn.jpush.im.android.api.JMessageClient; 23 | import cn.jpush.im.android.api.content.CustomContent; 24 | import cn.jpush.im.android.api.content.EventNotificationContent; 25 | import cn.jpush.im.android.api.content.FileContent; 26 | import cn.jpush.im.android.api.content.ImageContent; 27 | import cn.jpush.im.android.api.content.LocationContent; 28 | import cn.jpush.im.android.api.content.MessageContent; 29 | import cn.jpush.im.android.api.content.TextContent; 30 | import cn.jpush.im.android.api.content.VideoContent; 31 | import cn.jpush.im.android.api.content.VoiceContent; 32 | import cn.jpush.im.android.api.enums.ConversationType; 33 | import cn.jpush.im.android.api.enums.MessageDirect; 34 | import cn.jpush.im.android.api.model.ChatRoomInfo; 35 | import cn.jpush.im.android.api.model.Conversation; 36 | import cn.jpush.im.android.api.model.GroupBasicInfo; 37 | import cn.jpush.im.android.api.model.GroupInfo; 38 | import cn.jpush.im.android.api.model.GroupMemberInfo; 39 | import cn.jpush.im.android.api.model.Message; 40 | import cn.jpush.im.android.api.model.UserInfo; 41 | 42 | class JsonUtils { 43 | 44 | static Map fromJson(JSONObject jsonObject) { 45 | Map map = new HashMap(); 46 | try { 47 | Iterator keysItr = jsonObject.keys(); 48 | while (keysItr.hasNext()) { 49 | String key = keysItr.next(); 50 | String value = jsonObject.getString(key); 51 | map.put(key, value); 52 | } 53 | } catch (JSONException e) { 54 | 55 | } 56 | 57 | return map; 58 | } 59 | 60 | static HashMap toJson(Map map) { 61 | HashMap result = new HashMap(); 62 | Iterator iterator = map.keySet().iterator(); 63 | 64 | // JSONObject jsonObject = new JSONObject(); 65 | while (iterator.hasNext()) { 66 | String key = iterator.next(); 67 | 68 | result.put(key, map.get(key)); 69 | } 70 | return result; 71 | } 72 | 73 | static HashMap toJson(final UserInfo userInfo) { 74 | if (userInfo == null) { 75 | return null; 76 | } 77 | 78 | final HashMap result = new HashMap(); 79 | 80 | result.put("type", "user"); 81 | 82 | if (null != userInfo.getGender()) { 83 | switch (userInfo.getGender()) { 84 | case male: 85 | result.put("gender", "male"); 86 | break; 87 | case female: 88 | result.put("gender", "female"); 89 | break; 90 | case unknown: 91 | result.put("gender", "unknown"); 92 | 93 | } 94 | } else { 95 | result.put("gender", "unknown"); 96 | } 97 | 98 | result.put("username", userInfo.getUserName() != null ? userInfo.getUserName() : ""); 99 | result.put("appKey", userInfo.getAppKey()); 100 | result.put("nickname", userInfo.getNickname() != null ? userInfo.getNickname() : ""); 101 | if (userInfo.getAvatarFile() != null) { 102 | result.put("avatarThumbPath", userInfo.getAvatarFile().getAbsolutePath()); 103 | } else { 104 | result.put("avatarThumbPath", ""); 105 | } 106 | 107 | if (userInfo.getBirthday() != 0) { 108 | DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); 109 | try { 110 | String tsStr = sdf.format(userInfo.getBirthday()); 111 | result.put("birthday", tsStr); 112 | } catch (Exception e) { 113 | e.printStackTrace(); 114 | } 115 | } else { 116 | long time = userInfo.getBirthday(); 117 | result.put("birthday", ""); 118 | } 119 | 120 | result.put("region", userInfo.getRegion() != null ? userInfo.getRegion() : ""); 121 | result.put("signature", userInfo.getSignature() != null ? userInfo.getSignature() : ""); 122 | result.put("address", userInfo.getAddress() != null ? userInfo.getAddress() : ""); 123 | result.put("noteName", userInfo.getNotename() != null ? userInfo.getNotename() : ""); 124 | result.put("noteText", userInfo.getNoteText() != null ? userInfo.getNoteText() : ""); 125 | result.put("isNoDisturb", userInfo.getNoDisturb() == 1); 126 | result.put("isInBlackList", userInfo.getBlacklist() == 1); 127 | result.put("isFriend", userInfo.isFriend()); 128 | Map extras = userInfo.getExtras(); 129 | result.put("extras", extras != null ? extras : new HashMap()); 130 | return result; 131 | } 132 | 133 | static HashMap toJson(GroupInfo groupInfo) { 134 | 135 | final HashMap result = new HashMap(); 136 | 137 | result.put("type", "group"); 138 | result.put("id", String.valueOf(groupInfo.getGroupID())); 139 | 140 | switch (groupInfo.getGroupType()) { 141 | case public_group: { 142 | } 143 | result.put("groupType", "public"); 144 | break; 145 | default: 146 | result.put("groupType", "private"); 147 | break; 148 | } 149 | 150 | result.put("name", groupInfo.getGroupName()); 151 | result.put("desc", groupInfo.getGroupDescription()); 152 | result.put("level", groupInfo.getGroupLevel()); 153 | result.put("owner", groupInfo.getGroupOwner() != null ? groupInfo.getGroupOwner() : ""); 154 | GroupMemberInfo memberInfo = groupInfo.getOwnerMemberInfo(); 155 | // 156 | // if (memberInfo != null) { 157 | // 158 | // result.put("owner", memberInfo.getUserInfo().getUserName()); 159 | // } 160 | 161 | // result.put("ownerAppKey", groupInfo.getOwnerMemberInfo().getUserInfo().getAppKey()); 162 | result.put("ownerAppKey", groupInfo.getOwnerAppkey() != null ? groupInfo.getOwnerAppkey() : ""); 163 | result.put("maxMemberCount", groupInfo.getMaxMemberCount()); 164 | result.put("isNoDisturb", groupInfo.getNoDisturb() == 1); 165 | result.put("isBlocked", groupInfo.isGroupBlocked() == 1); 166 | 167 | return result; 168 | } 169 | 170 | static HashMap toJson(GroupMemberInfo groupMemberInfo) { 171 | 172 | final HashMap result = new HashMap(); 173 | result.put("user", toJson(groupMemberInfo.getUserInfo())); 174 | result.put("groupNickname", groupMemberInfo.getNickName()); 175 | 176 | if (groupMemberInfo.getType() == GroupMemberInfo.Type.group_owner) { 177 | result.put("memberType", "owner"); 178 | } else if (groupMemberInfo.getType() == GroupMemberInfo.Type.group_keeper) { 179 | result.put("memberType", "admin"); 180 | } else { 181 | result.put("memberType", "ordinary"); 182 | } 183 | result.put("joinGroupTime", groupMemberInfo.getJoinGroupTime()); 184 | 185 | return result; 186 | } 187 | 188 | static HashMap toJson(GroupBasicInfo groupInfo) { 189 | final HashMap result = new HashMap(); 190 | result.put("type", "group"); 191 | result.put("id", String.valueOf(groupInfo.getGroupID())); 192 | result.put("name", groupInfo.getGroupName()); 193 | result.put("desc", groupInfo.getGroupDescription()); 194 | result.put("level", groupInfo.getGroupLevel()); 195 | result.put("avatarThumbPath", groupInfo.getAvatar()); 196 | result.put("maxMemberCount", groupInfo.getMaxMemberCount());//String.valueOf(groupInfo.getMaxMemberCount()) 197 | switch (groupInfo.getGroupType()) { 198 | case public_group: { 199 | } 200 | result.put("groupType", "public"); 201 | break; 202 | default: 203 | result.put("groupType", "private"); 204 | break; 205 | } 206 | 207 | return result; 208 | } 209 | 210 | static HashMap toJson(Message msg) { 211 | 212 | final HashMap result = new HashMap(); 213 | 214 | result.put("id", String.valueOf(msg.getId())); // 本地数据库 id 215 | result.put("serverMessageId", String.valueOf(msg.getServerMessageId())); // 服务器端 id 216 | result.put("from", toJson(msg.getFromUser())); // 消息发送者 217 | 218 | boolean isSend = msg.getDirect().equals(MessageDirect.send); 219 | result.put("isSend", isSend); // 消息是否是由当前用户发出 220 | 221 | HashMap targetJson = null; 222 | switch (msg.getTargetType()) { 223 | case single: 224 | if (isSend) { // 消息发送 225 | targetJson = toJson((UserInfo) msg.getTargetInfo()); 226 | } else { // 消息接收 227 | targetJson = toJson(JMessageClient.getMyInfo()); 228 | } 229 | break; 230 | case group: 231 | targetJson = toJson((GroupInfo) msg.getTargetInfo()); 232 | break; 233 | case chatroom: 234 | targetJson = toJson((ChatRoomInfo) msg.getTargetInfo()); 235 | break; 236 | default: 237 | } 238 | result.put("target", targetJson); 239 | switch (msg.getStatus()) { 240 | case created: 241 | result.put("state", "draft"); 242 | break; 243 | case send_going: 244 | result.put("state", "sending"); 245 | break; 246 | case send_fail: 247 | result.put("state", "send_failed"); 248 | break; 249 | case send_draft: 250 | result.put("state", "draft"); 251 | break; 252 | case receive_fail: 253 | result.put("state", "download_failed"); 254 | break; 255 | case send_success: 256 | result.put("state", "send_succeed"); 257 | break; 258 | case receive_going: 259 | result.put("state", "receiving"); 260 | break; 261 | case receive_success: 262 | result.put("state", "received"); 263 | break; 264 | } 265 | MessageContent content = msg.getContent(); 266 | if (content.getStringExtras() != null) { 267 | result.put("extras", content.getStringExtras()); 268 | } else { 269 | result.put("extras", new HashMap()); 270 | } 271 | 272 | result.put("createTime", msg.getCreateTime()); 273 | 274 | switch (msg.getContentType()) { 275 | case text: 276 | result.put("type", "text"); 277 | result.put("text", ((TextContent) content).getText()); 278 | break; 279 | case image: 280 | result.put("type", "image"); 281 | result.put("thumbPath", ((ImageContent) content).getLocalThumbnailPath()); 282 | break; 283 | case voice: 284 | result.put("type", "voice"); 285 | result.put("path", ((VoiceContent) content).getLocalPath()); 286 | result.put("duration", ((VoiceContent) content).getDuration() + 0.0); 287 | break; 288 | case file: 289 | result.put("type", "file"); 290 | result.put("fileName", ((FileContent) content).getFileName()); 291 | break; 292 | case custom: 293 | result.put("type", "custom"); 294 | Map customObject = ((CustomContent) content).getAllStringValues(); 295 | result.put("customObject", toJson(customObject)); 296 | break; 297 | case location: 298 | result.put("type", "location"); 299 | result.put("latitude", ((LocationContent) content).getLatitude().doubleValue()); 300 | result.put("longitude", ((LocationContent) content).getLongitude().doubleValue()); 301 | result.put("address", ((LocationContent) content).getAddress()); 302 | result.put("scale", ((LocationContent) content).getScale().intValue()); 303 | break; 304 | case video: 305 | result.put("type", "video"); 306 | result.put("duration", ((VideoContent) content).getDuration()); 307 | result.put("videoPath", ((VideoContent) content).getVideoLocalPath()); 308 | result.put("thumbImagePath", ((VideoContent) content).getThumbLocalPath()); 309 | result.put("videoFileName", ((VideoContent) content).getFileName()); 310 | result.put("thumbFormat", ((VideoContent) content).getThumbFormat()); 311 | break; 312 | case eventNotification: 313 | result.put("type", "event"); 314 | List usernameList = ((EventNotificationContent) content).getUserNames(); 315 | if (usernameList != null) { 316 | result.put("usernames", toJson(usernameList)); 317 | } 318 | Log.d("flutter plugin", "usernameList:" + usernameList); 319 | 320 | List displayNameList = ((EventNotificationContent) content).getUserDisplayNames(); 321 | if (displayNameList != null) { 322 | result.put("nicknames", toJson(displayNameList)); 323 | } 324 | Log.d("flutter plugin", "displayNameList:" + displayNameList); 325 | 326 | switch (((EventNotificationContent) content).getEventNotificationType()) { 327 | case group_member_added: 328 | // 群成员加群事件 329 | result.put("eventType", "group_member_added"); 330 | break; 331 | case group_member_removed: 332 | // 群成员被踢事件 333 | result.put("eventType", "group_member_removed"); 334 | break; 335 | case group_member_exit: 336 | // 群成员退群事件 337 | result.put("eventType", "group_member_exit"); 338 | break; 339 | case group_info_updated: 340 | result.put("eventType", "group_info_updated"); 341 | break; 342 | case group_member_keep_silence: 343 | result.put("eventType", "group_member_keep_silence"); 344 | break; 345 | case group_member_keep_silence_cancel: 346 | result.put("eventType", "group_member_keep_silence_cancel"); 347 | break; 348 | case group_keeper_added: 349 | result.put("eventType", "group_keeper_added"); 350 | break; 351 | case group_keeper_removed: 352 | result.put("eventType", "group_keeper_removed"); 353 | break; 354 | case group_dissolved: 355 | // 解散群组事件 356 | result.put("eventType", "group_dissolved"); 357 | break; 358 | case group_owner_changed: 359 | // 移交群组事件 360 | result.put("eventType", "group_owner_changed"); 361 | break; 362 | case group_type_changed: 363 | // 移交群组事件 364 | result.put("eventType", "group_type_changed"); 365 | break; 366 | default: 367 | } 368 | default: 369 | } 370 | return result; 371 | } 372 | 373 | static Message JsonToMessage(JSONObject json) { 374 | Conversation conversation = null; 375 | int msgId = 0; 376 | 377 | try { 378 | msgId = Integer.parseInt(json.getString("id")); 379 | boolean isSend = json.getBoolean("isSend"); 380 | 381 | JSONObject target = json.getJSONObject("target"); 382 | 383 | if (target.getString("type").equals("user")) { 384 | String username; 385 | String appKey; 386 | 387 | if (isSend) { // 消息由当前用户发送,则聊天对象为消息接收方。 388 | username = target.getString("username"); 389 | appKey = target.has("appKey") ? target.getString("appKey") : null; 390 | 391 | } else { // 当前用户为消息接收方,则聊天对象为消息发送方。 392 | JSONObject opposite = json.getJSONObject("from"); 393 | username = opposite.getString("username"); 394 | appKey = opposite.has("appKey") ? opposite.getString("appKey") : null; 395 | } 396 | 397 | conversation = JMessageClient.getSingleConversation(username, appKey); 398 | 399 | } else if (target.getString("type").equals("group")) { 400 | long groupId = Long.parseLong(target.getString("id")); 401 | conversation = JMessageClient.getGroupConversation(groupId); 402 | 403 | } else if (target.getString("type").equals("chatRoom")) { 404 | long roomId = Long.parseLong(target.getString("roomId")); 405 | conversation = JMessageClient.getChatRoomConversation(roomId); 406 | } 407 | } catch (JSONException e) { 408 | e.printStackTrace(); 409 | } 410 | 411 | return conversation != null ? conversation.getMessage(msgId) : null; 412 | } 413 | 414 | static HashMap toJson(Conversation conversation) { 415 | 416 | final HashMap json = new HashMap(); 417 | json.put("title", conversation.getTitle() != null ? conversation.getTitle() : ""); 418 | json.put("unreadCount", conversation.getUnReadMsgCnt()); 419 | 420 | if (conversation.getLatestMessage() != null) { 421 | json.put("latestMessage", toJson(conversation.getLatestMessage())); 422 | } 423 | 424 | if (conversation.getType() == ConversationType.single) { 425 | UserInfo targetInfo = (UserInfo) conversation.getTargetInfo(); 426 | json.put("conversationType", "single"); 427 | json.put("target", toJson(targetInfo)); 428 | 429 | } else if (conversation.getType() == ConversationType.group) { 430 | GroupInfo targetInfo = (GroupInfo) conversation.getTargetInfo(); 431 | json.put("conversationType", "group"); 432 | json.put("target", toJson(targetInfo)); 433 | } else if (conversation.getType() == ConversationType.chatroom) { 434 | ChatRoomInfo chatRoom = (ChatRoomInfo) conversation.getTargetInfo(); 435 | json.put("target", toJson(chatRoom)); 436 | json.put("conversationType", "chatRoom"); 437 | } 438 | 439 | if (!TextUtils.isEmpty(conversation.getExtra())) { 440 | HashMap extrasMap = new HashMap(); 441 | String extras = conversation.getExtra(); 442 | JsonParser parser = new JsonParser(); 443 | JsonObject jsonObject = parser.parse(extras).getAsJsonObject(); 444 | for (Map.Entry entry : jsonObject.entrySet()) { 445 | extrasMap.put(entry.getKey(), entry.getValue().toString()); 446 | } 447 | json.put("extras", extrasMap); 448 | } else { 449 | json.put("extras", new HashMap()); 450 | } 451 | 452 | Log.d("flutter plugin", "native the conversation:" + json.toString()); 453 | 454 | return json; 455 | } 456 | 457 | static List toJson(List list) { 458 | 459 | List jsonArray = new ArrayList(); 460 | 461 | if (list == null) { 462 | return jsonArray; 463 | } 464 | 465 | for (Object object : list) { 466 | 467 | if (object instanceof UserInfo) { 468 | jsonArray.add(toJson((UserInfo) object)); 469 | } else if (object instanceof GroupInfo) { 470 | jsonArray.add(toJson((GroupInfo) object)); 471 | } else if (object instanceof GroupBasicInfo) { 472 | jsonArray.add(toJson((GroupBasicInfo) object)); 473 | } else if (object instanceof Message) { 474 | jsonArray.add(toJson((Message) object)); 475 | } else if (object instanceof GroupMemberInfo) { 476 | jsonArray.add(toJson((GroupMemberInfo) object)); 477 | } else { 478 | jsonArray.add(object); 479 | } 480 | } 481 | 482 | return jsonArray; 483 | } 484 | 485 | static HashMap toJson(String eventName, JSONObject value) { 486 | final HashMap result = new HashMap(); 487 | result.put("eventName", eventName); 488 | result.put("value", value); 489 | return result; 490 | } 491 | 492 | static HashMap toJson(String eventName, JSONArray value) { 493 | final HashMap result = new HashMap(); 494 | result.put("eventName", eventName); 495 | result.put("value", value); 496 | return result; 497 | } 498 | 499 | static HashMap toJson(ChatRoomInfo chatRoomInfo) { 500 | 501 | final HashMap json = new HashMap(); 502 | json.put("type", "chatRoom"); 503 | json.put("roomId", String.valueOf(chatRoomInfo.getRoomID())); // 配合 iOS,将 long 转成 String。 504 | json.put("name", chatRoomInfo.getName() != null ? chatRoomInfo.getName() : ""); 505 | json.put("appKey", chatRoomInfo.getAppkey()); 506 | json.put("description", chatRoomInfo.getDescription() != null ? chatRoomInfo.getDescription() : ""); 507 | json.put("createTime", chatRoomInfo.getCreateTime()); // 创建日期,单位秒。 508 | json.put("maxMemberCount", chatRoomInfo.getMaxMemberCount()); // 最大成员数。 509 | json.put("memberCount", chatRoomInfo.getTotalMemberCount()); // 当前成员数。 510 | return json; 511 | } 512 | } 513 | -------------------------------------------------------------------------------- /android/src/main/java/com/jiguang/jmessageflutter/PushService.java: -------------------------------------------------------------------------------- 1 | package com.jiguang.jmessageflutter; 2 | 3 | import cn.jpush.android.service.JCommonService; 4 | 5 | public class PushService extends JCommonService { 6 | 7 | } 8 | -------------------------------------------------------------------------------- /documents/APIs.md: -------------------------------------------------------------------------------- 1 | # API 2 | 3 | #### Usage 4 | ```dart 5 | import 'package:jmessage_flutter/jmessage_flutter.dart'; 6 | 7 | JmessageFlutter JMessage = JmessageFlutter(); 8 | ``` 9 | 10 | - [初始化](#初始化) 11 | - [init](#init) 12 | - [setDebugMode](#setdebugmode) 13 | - [setBadge](#setbadge) 14 | - [applyPushAuthority](#applyPushAuthority) 15 | - [用户登录、注册及属性维护](#用户登录注册及属性维护) 16 | - [userRegister](#userregister) 17 | - [login](#login) 18 | - [logout](#logout) 19 | - [getMyInfo](#getmyinfo) 20 | - [getUserInfo](#getuserinfo) 21 | - [updateMyPassword](#updatemypassword) 22 | - [updateMyAvatar](#updatemyavatar) 23 | - [updateMyInfo](#updatemyinfo) 24 | - [downloadThumbUserAvatar](#downloadthumbuseravatar) 25 | - [downloadOriginalUserAvatar](#downloadoriginaluseravatar) 26 | - [群组](#群组) 27 | - [createGroup](#creategroup) 28 | - [addGroupAdmins](#addgroupadmins) 29 | - [removeGroupAdmins](#removegroupadmins) 30 | - [changeGroupType](#changegrouptype) 31 | - [getPublicGroupInfos](#getpublicgroupinfos) 32 | - [applyJoinGroup](#applyjoingroup) 33 | - [processApplyJoinGroup](#processapplyjoingroup) 34 | - [dissolveGroup](#dissolvegroup) 35 | - [getGroupIds](#getgroupids) 36 | - [getGroupInfo](#getgroupinfo) 37 | - [getGroupMembers](#getgroupmembers) 38 | - [updateGroupInfo](#updategroupinfo) 39 | - [addGroupMembers](#addgroupmembers) 40 | - [removeGroupMembers](#removegroupmembers) 41 | - [聊天](#聊天) 42 | - [createMessage](#createmessage) 43 | - [sendMessage](#sendmessage) 44 | - [sendTextMessage](#sendtextmessage) 45 | - [sendImageMessage](#sendimagemessage) 46 | - [sendVoiceMessage](#sendvoicemessage) 47 | - [sendCustomMessage](#sendcustommessage) 48 | - [sendLocationMessage](#sendlocationmessage) 49 | - [sendFileMessage](#sendfilemessage) 50 | - [retractMessage](#retractmessage) 51 | - [getHistoryMessages](#gethistorymessages) 52 | - [downloadOriginalImage](#downloadoriginalimage) 53 | - [downloadThumbImage](#downloadthumbimage) 54 | - [downloadVoiceFile](#downloadvoicefile) 55 | - [downloadFile](#downloadfile) 56 | - [会话](#会话) 57 | - [createConversation](#createconversation) 58 | - [deleteConversation](#deleteconversation) 59 | - [enterConversation](#enterconversation) 60 | - [exitConversation](#exitconversation) 61 | - [getConversation](#getconversation) 62 | - [getConversations](#getconversations) 63 | - [getAllUnreadCount](#getallunreadcount) 64 | - [resetUnreadMessageCount](#resetunreadmessagecount) 65 | - [聊天室](#聊天室) 66 | - [getChatRoomListByApp](#getchatroomlistbyapp) 67 | - [getChatRoomListByUser](#getchatroomlistbyuser) 68 | - [getChatRoomInfos](#getchatroominfos) 69 | - [getChatRoomOwner](#getchatroomowner) 70 | - [enterChatRoom](#enterchatroom) 71 | - [leaveChatRoom](#leavechatroom) 72 | - [getChatRoomConversationList](#getchatroomconversationlist) 73 | - [好友](#好友) 74 | - [sendInvitationRequest](#sendinvitationrequest) 75 | - [acceptInvitation](#acceptInvitation) 76 | - [declineInvitation](#declineinvitation) 77 | - [getFriends](#getfriends) 78 | - [removeFromFriendList](#removefromfriendlist) 79 | - [updateFriendNoteName](#updatefriendnotename) 80 | - [updateFriendNoteText](#updatefriendnotetext) 81 | - [事件监听]() 82 | - [消息事件](#addreceivemessagelistener) 83 | - [addReceiveMessageListener](#addreceivemessagelistener) 84 | - [removeReceiveMessageListener](#addreceivemessagelistener) 85 | - [addReceiveChatRoomMsgListener](#addreceivechatroommsglistener) 86 | - [removeReceiveChatRoomMsgListener](#removereceivechatroommsglistener) 87 | - [离线消息](#addsyncofflinemessagelistener) 88 | - [addSyncOfflineMessageListener](#addsyncofflinemessagelistener) 89 | - [removeSyncOfflineMessageListener](#addsyncofflinemessagelistener) 90 | - [消息漫游](#addsyncroamingmessagelistener) 91 | - [addSyncRoamingMessageListener](#addsyncroamingmessagelistener) 92 | - [removeSyncRoamingMessageListener](#addsyncroamingmessagelistener) 93 | - [好友请求事件](#addcontactnotifylistener) 94 | - [addContactNotifyListener](#addcontactnotifylistener) 95 | - [removeContactNotifyListener](#addcontactnotifylistener) 96 | - [接收到消息撤回事件](#addmessageretractlistener) 97 | - [addMessageRetractListener](#addmessageretractlistener) 98 | - [removeMessageRetractListener](#addmessageretractlistener) 99 | - [登录状态变更](#addloginstatechangedlistener) 100 | - [addLoginStateChangedListener](#addloginstatechangedlistener) 101 | - [removeLoginStateChangedListener](#addloginstatechangedlistener) 102 | - [监听接收入群申请事件](#addreceiveapplyjoingroupapprovallistener) 103 | - [addReceiveApplyJoinGroupApprovalListener](#addreceiveapplyjoingroupapprovallistener) 104 | - [removeReceiveApplyJoinGroupApprovalListener](#removereceiveapplyjoingroupapprovallistener) 105 | - [监听管理员拒绝入群申请事件](#addreceivegroupadminrejectlistener) 106 | - [addReceiveGroupAdminRejectListener](#addreceivegroupadminrejectlistener) 107 | - [removeReceiveGroupAdminRejectListener](#removereceivegroupadminrejectlistener) 108 | - [监听管理员同意入群申请事件](#addreceivegroupadminapprovallistener) 109 | - [addReceiveGroupAdminApprovalListener](#addreceivegroupadminapprovallistener) 110 | - [removeReceiveGroupAdminApprovalListener](#removereceivegroupadminapprovallistener) 111 | 112 | 113 | - [点击消息通知事件(Android Only)](#addclickmessagenotificationlistener) 114 | - [addClickMessageNotificationListener](#addclickmessagenotificationlistener) 115 | - [removeClickMessageNotificationListener](#addclickmessagenotificationlistener) 116 | 117 | ## 初始化 118 | 119 | ### init 120 | 121 | **注意 Android 仍需在 build.gradle 中配置 appKey,具体可以[参考这个文件](https://github.com/jpush/jmessage-react-plugin/blob/dev/example/android/app/build.gradle)** 122 | 初始化插件。建议在应用起始页的构造函数中调用。 123 | 124 | #### 示例 125 | 126 | ```dart 127 | JMessage.init(isOpenMessageRoaming: true, appkey: kMockAppkey); 128 | ``` 129 | 130 | #### 参数说明 131 | 132 | - appkey:极光官网注册的应用 AppKey。**Android 仍需配置 app 下 build.gradle 中的 AppKey。** 133 | - isOpenMessageRoaming:是否开启消息漫游,不传默认关闭。 134 | - isProduction:是否为生产模式。 135 | - channel:(选填)应用的渠道名称。 136 | 137 | ### setDebugMode 138 | 139 | 设置是否开启 debug 模式,开启后 SDK 将会输出更多日志信息,推荐在应用对外发布时关闭。 140 | 141 | #### 示例 142 | 143 | ```dart 144 | JMessage.setDebugMode( enable: true ); 145 | ``` 146 | 147 | #### 参数说明 148 | 149 | - enable:为 true 打开 Debug 模式,false 关闭 Debug 模式。 150 | 151 | ### setBadge 152 | 153 | 设置 badge 值,该操作会设置本地应用的 badge 值,同时设置极光服务器的 badge 值,收到消息 badge +1 会在极光服务器 badge 的基础上累加。 154 | 155 | #### 示例 156 | 157 | ```dart 158 | await JMessage.setBadge(badge: 5); 159 | ``` 160 | 161 | ### applyPushAuthority 162 | 163 | iOS 端注册 apns 通知 164 | 165 | #### 示例 166 | 167 | ```dart 168 | jmessage.applyPushAuthority( 169 | new JMNotificationSettingsIOS( 170 | sound: true, 171 | alert: true, 172 | badge: true) 173 | ); 174 | ``` 175 | 176 | ## 用户登录、注册及属性维护 177 | 178 | ### userRegister 179 | 180 | 用户注册。 181 | 182 | #### 示例 183 | 184 | ```dart 185 | // 注册 186 | await JMessage.userRegister( 187 | username: "登录用户名", 188 | password: "登录密码" 189 | ); 190 | ``` 191 | 192 | #### 参数说明 193 | 194 | - username: 用户名。在应用中用于唯一标识用户,必须唯一。支持以字母或者数字开头,支持字母、数字、下划线、英文点(.)、减号、@。长度限制:Byte(4~128)。 195 | - password: 用户密码。不限制字符。长度限制:Byte(4~128)。 196 | - nickname: 昵称 197 | 198 | ### login 199 | 200 | ```dart 201 | // 登录 202 | await JMessage.login({ 203 | username: "登录用户名", 204 | password: "登录密码" 205 | }); 206 | ``` 207 | 208 | #### 参数说明 209 | 210 | - username: 用户名。 211 | - password: 用户密码。 212 | 213 | ### logout 214 | 215 | 用户登出。 216 | 217 | #### 示例 218 | 219 | ```dart 220 | JMessage.logout(); 221 | ``` 222 | 223 | ### getMyInfo 224 | 225 | 获取当前登录用户信息。如果未登录返回的 user 对象里面的数据为空,例如 user.username 为空。可以用于判断用户登录状态 226 | 227 | #### 示例 228 | 229 | ```dart 230 | JMUserInfo user = await JMessage.getMyInfo(); 231 | ``` 232 | 233 | ### getUserInfo 234 | 235 | 获取用户信息。该接口可以获取不同 AppKey 下(即不同应用)的用户信息,如果 AppKey 为空,则默认为当前应用下。 236 | 237 | #### 示例 238 | 239 | ```dart 240 | JMUserInfo user = await JMessage.getUserInfo( username: 'username', appKey: 'your_app_key' ); 241 | ``` 242 | 243 | ### updateMyPassword 244 | 245 | 更新当前登录用户的密码。 246 | 247 | #### 示例 248 | 249 | ```dart 250 | await JMessage.updateMyPassword( oldPwd: 'old_password', newPwd: 'new_password' ); 251 | ``` 252 | 253 | ### updateMyAvatar 254 | 255 | 更新当前登录用户的头像。 256 | 257 | #### 示例 258 | 259 | ```dart 260 | await JMessage.updateMyAvatar( imgPath: 'img_local_path' ); 261 | ``` 262 | 263 | #### 参数说明 264 | 265 | - imgPath: 本地图片文件的绝对路径地址。注意在 Android 6.0 及以上版本系统中,需要动态请求 `WRITE_EXTERNAL_STORAGE` 权限。 266 | 两个系统中的图片路径分别类似于: 267 | - Android:`/storage/emulated/0/DCIM/Camera/IMG_20160526_130223.jpg` 268 | - iOS:`/var/mobile/Containers/Data/Application/7DC5CDFF-6581-4AD3-B165-B604EBAB1250/tmp/photo.jpg` 269 | 270 | ### updateMyInfo 271 | 272 | 更新当前登录用户信息。包括了:昵称(nickname)、生日(birthday)、个性签名(signature)、性别(gender)、地区(region)和具体地址(address)。 273 | 274 | #### 示例 275 | 276 | ```dart 277 | await JMessage.updateMyInfo( nickname: 'nickname' ); 278 | ``` 279 | 280 | #### 参数说明 281 | 282 | - nickname: 昵称。不支持字符 "\n" 和 "\r";长度限制:Byte (0~64)。 283 | - birthday: (Number)生日日期的毫秒数。 284 | 285 | ### downloadThumbUserAvatar 286 | 287 | 下载用户头像缩略图。 288 | 289 | #### 示例 290 | 291 | ```dart 292 | Map resJson = await JMessage.downloadThumbUserAvatar( 293 | username: 'theUserName', 294 | appKey: 'you appKey'); 295 | resJson = { 296 | 'username': 'user name ', 297 | 'appKey': 'appKey', 298 | 'filePath': 'filePath' 299 | }; 300 | ``` 301 | 302 | #### 参数说明: 303 | 304 | - username (string): 用户名 305 | - appKey (string): 不传默认是本应用 appkey。 306 | 307 | 308 | - resJson (Map): 309 | - username (string): 用户名 310 | - appKey (string): 311 | - filePath (string): 下载后的图片路径(本地路径) 312 | 313 | ### downloadOriginalUserAvatar 314 | 315 | 下载用户头像原图。 316 | 317 | #### 示例 318 | 319 | ```dart 320 | const param = { 321 | username: 'theUserName', 322 | appKey: 'you appKey' 323 | } 324 | Map resJson = await JMessage.downloadOriginalUserAvatar( 325 | username: 'theUserName', 326 | appKey: 'you appKey' 327 | ); 328 | 329 | resJson = { 330 | 'username': 'user name ', 331 | 'appKey': 'appKey', 332 | 'filePath': 'filePath' 333 | }; 334 | ``` 335 | 336 | #### 参数说明: 337 | 338 | - username (string): 用户名 339 | - appKey (string): 不传默认是本应用 appkey。 340 | - result (object): 341 | - username (string): 用户名 342 | - appKey (string): 343 | - filePath (string): 下载后的图片路径 344 | 345 | ## 群组 346 | 347 | ### createGroup 348 | 349 | 创建群组。 350 | 351 | #### 示例 352 | 353 | ```dart 354 | JMessage.createGroup( name: 'group_name', desc: 'group_desc' ); 355 | ``` 356 | 357 | #### 参数说明 358 | 359 | - name (string): 群组名。不支持 "\n" 和 "\r" 字符,长度限制为 0 ~ 64 Byte。 360 | - groupType (string): 指定创建群的类型,可以为 'private' 和 'public', 默认为 private。 361 | - desc (string): 群组描述。长度限制为 0 ~ 250 Byte。 362 | 363 | ### dissolveGroup 364 | 365 | 解散群 366 | 367 | #### 示例 368 | 369 | ```dart 370 | await JMessage.dissolveGroup( groupId: 'group_id' ); 371 | ``` 372 | 373 | #### 参数说明 374 | 375 | - groupId (string): 要解散的群组 id。 376 | 377 | ### getGroupIds 378 | 379 | 获取当前用户群组 380 | 381 | #### 示例 382 | 383 | ```dart 384 | List gids = await JMessage.getGroupIds(); 385 | ``` 386 | 387 | #### 参数说明 388 | 389 | 无 390 | 391 | ### getGroupInfo 392 | 393 | 根据群组id获取群组信息 394 | 395 | #### 示例 396 | 397 | ```dart 398 | JMessage.getGroupInfo( id: "1234567" ) 399 | ``` 400 | 401 | #### 参数说明 402 | 403 | - id(string): 指定群组 404 | 405 | ### getGroupMembers 406 | 407 | 获取群成员。 408 | 409 | #### 示例 410 | 411 | ```dart 412 | Listmembers = await JMessage.getGroupMembers( id: 'groupId'); 413 | ``` 414 | 415 | ### updateGroupInfo 416 | 417 | 更新群组信息。 418 | 419 | #### 示例 420 | 421 | ```dart 422 | await JMessage.updateGroupInfo( id: 'groupId' ,newName: 'group_name', newDesc: 'group_desc' ); 423 | ``` 424 | 425 | #### 参数说明 426 | 427 | - id (string): 指定操作的群 groupId 428 | - newName (string): 群组名。不支持 "\n" 和 "\r" 字符,长度限制为 0 ~ 64 Byte。 429 | - newDesc (string): 群组描述。长度限制为 0 ~ 250 Byte。 430 | 431 | ### addGroupMembers 432 | 433 | 批量添加群成员 434 | 435 | #### 示例 436 | 437 | ```dart 438 | await JMessage.addGroupAdmins( 439 | id: 'group_id', 440 | usernames: ['ex_username1', 'ex_username2'], 441 | appKey: 'appkey' 442 | ); 443 | ``` 444 | 445 | #### 参数说明 446 | 447 | - id: 指定操作的群 groupId 448 | - usernames: 被添加的的用户名数组。 449 | - appKey: 被添加用户所属应用的 AppKey。如果不填,默认为当前应用。 450 | 451 | ### removeGroupMembers 452 | 453 | 批量删除群成员 454 | 455 | #### 示例 456 | 457 | ```dart 458 | await JMessage.removeGroupMembers( 459 | id: 'group_id', 460 | usernames: ['ex_username1', 'ex_username2'], 461 | appKey: 'appkey' ); 462 | ``` 463 | 464 | #### 参数说明 465 | 466 | - id : 指定操作的群 groupId 467 | - username : 被添加的的用户名数组。 468 | - appKey: 被添加用户所属应用的 AppKey。如果不填,默认为当前应用。 469 | 470 | ### addGroupAdmins 471 | 472 | 批量添加管理员 473 | 474 | #### 示例 475 | 476 | ```dart 477 | await JMessage.addGroupAdmins( 478 | groupId: 'group_id', 479 | usernames: ['ex_username1', 'ex_username2'] 480 | ); 481 | ``` 482 | 483 | #### 参数说明 484 | 485 | - groupId (string): 指定操作的群 groupId。 486 | - usernames : 被添加的的用户名数组。 487 | 488 | ### removeGroupAdmins 489 | 490 | 批量删除管理员 491 | 492 | #### 示例 493 | 494 | ```dart 495 | await JMessage.removeGroupAdmins( 496 | groupId: 'group_id', 497 | usernames: ['ex_username1', 'ex_username2'] 498 | ); 499 | ``` 500 | 501 | #### 参数说明 502 | 503 | - groupId (string): 指定操作的群 groupId。 504 | - usernames : 被移除的的用户名数组。 505 | 506 | ### changeGroupType 507 | 508 | 修改群类型 509 | 510 | #### 示例 511 | 512 | ```dart 513 | await JMessage.changeGroupType( 514 | groupId: 'group_id', 515 | type: 'public' 516 | ); 517 | ``` 518 | 519 | #### 参数说明 520 | 521 | - groupId (string): 指定操作的群 groupId。 522 | - type : 公有群(类似 QQ 群进群需要管理员以上人员审批),私有群(类似微信群直接邀请就能进)。 523 | 524 | ### getPublicGroupInfos 525 | 526 | 分页获取指定 appKey 下的共有群 527 | 528 | #### 示例 529 | 530 | ```dart 531 | List groups = await JMessage.getPublicGroupInfos( 532 | appKey: 'my_appkey', 533 | start: 0, 534 | count: 20 535 | ); 536 | ``` 537 | 538 | #### 参数说明 539 | 540 | - appKey (string): 获取指定 appkey 541 | - start (int): 开始的位置 542 | - count (int): 获取的数量 543 | 544 | ### applyJoinGroup 545 | 546 | 申请入群(公开群) 547 | 548 | #### 示例 549 | 550 | ```dart 551 | await JMessage.applyJoinGroup( 552 | groupId: 'group_id', 553 | reason: 'Hello I from ...' 554 | ); 555 | ``` 556 | 557 | #### 558 | 559 | ### processApplyJoinGroup 560 | 561 | 批量处理入群(公开群)申请 562 | 563 | #### 示例 564 | 565 | ```dart 566 | await JMessage.processApplyJoinGroup( 567 | events: ['ex_event_id_1', 'ex_event_id_2'], 568 | reason: 'Hello I from ...' 569 | } 570 | ); 571 | ``` 572 | 573 | #### 参数说明 574 | 575 | - events (array): eventId 数组,当有用户申请入群的时候(或者被要求)会回调一个 event(通过 addReceiveApplyJoinGroupApprovalListener 监听),每个 event 会有个 id,用于审核入群操作。 576 | - reason (string): 入群理由。 577 | 578 | ## 聊天 579 | 580 | ### createMessage 581 | 582 | 创建消息,创建好消息后需要调用 [sendMessage](#sendMessage) 来发送消息。如果需要状态更新(发送中 -> 发送完成)可以使用这种方式,聊天室不支持该接口。 583 | 584 | ```dart 585 | var message = await jmessage.createMessage( 586 | type: JMMessageType.image, 587 | targetType: msg.from.targetType, 588 | path: msg.thumbPath, 589 | extras: {"key1": "value1"} 590 | ); 591 | ``` 592 | 593 | - type: 不同的消息类型需要不同的参数。 594 | - type = text 时 `text` 为必填。 595 | - type = image 时 `path` 为必填。 596 | - type = voice 时 `path` 为必填。 597 | - type = file 时 `path` 为必填。 598 | - type = location 时 `latitude` `longitude` 和 `scale` 为必填,`address` 选填。 599 | - type = custom 时 `customObject` 为必填。 600 | 601 | ### sendMessage 602 | 603 | 与 [createMessage](#createMessage) 配合使用,用于发送创建好的消息。 604 | 605 | ```dart 606 | var message = await jmessage.createMessage( 607 | type: JMMessageType.image, 608 | targetType: msg.from.targetType, 609 | path: msg.thumbPath, 610 | extras: {"key1": "value1"} 611 | ); 612 | 613 | var sendedMessage = await jmessage.sendMessage( 614 | message: message, 615 | sendOption: JMMessageSendOptions.fromJson({ 616 | 'isShowNotification': true, 617 | 'isRetainOffline': true, 618 | }) 619 | ); 620 | ``` 621 | 622 | 623 | 624 | ### sendTextMessage 625 | 626 | 发送文本消息。 627 | 628 | #### 示例 629 | 630 | ```dart 631 | JMTextMessage msg = await JMessage.sendTextMessage( 632 | type: kMockUser, 633 | text: 'Text Message Test!', 634 | ); 635 | ``` 636 | 637 | #### 参数说明 638 | 639 | - type: 会话类型。可以为 (JMSingle | JMGroup | JMChatRoom)。 640 | - text: 消息内容。 641 | - extras (Map): 自定义键值对,value 必须为字符串类型。 642 | - messageSendingOptions: 消息发送配置参数。支持的属性: 643 | - isShowNotification: 接收方是否针对此次消息发送展示通知栏通知。默认为 `true`。 644 | - isRetainOffline: 是否让后台在对方不在线时保存这条离线消息,等到对方上线后再推送给对方。默认为 `true`。 645 | - isCustomNotificationEnabled: 是否开启自定义接收方通知栏功能,设置为 `true` 后可设置下面的 `notificationTitle` 和 `notificationText`。默认未设置。 646 | - notificationTitle: 设置此条消息在接收方通知栏所展示通知的标题。 647 | - notificationText: 设置此条消息在接收方通知栏所展示通知的内容。 648 | 649 | ### sendImageMessage 650 | 651 | 发送图片消息,在收到消息时 SDK 默认会自动下载缩略图,如果要下载原图,需调用 `downloadOriginalImage` 方法。 652 | 653 | #### 示例 654 | 655 | ```dart 656 | JMessage.sendImageMessage( 657 | type: msg.from.targetType, 658 | path: msg.thumbPath, 659 | ) 660 | ``` 661 | 662 | #### 参数说明 663 | 664 | - type: 会话类型。可以为 (JMSingle | JMGroup | JMChatRoom)。 665 | - path: 本地图片的绝对路径。格式分别类似为: 666 | - Android:`/storage/emulated/0/DCIM/Camera/IMG_20160526_130223.jpg` 667 | - iOS:`/var/mobile/Containers/Data/Application/7DC5CDFF-6581-4AD3-B165-B604EBAB1250/tmp/photo.jpg` 668 | - extras: 自定义键值对,value 必须为字符串类型。 669 | - sendingOptions: 消息发送配置参数。支持的属性: 670 | - isShowNotification: 接收方是否针对此次消息发送展示通知栏通知。默认为 `true`。 671 | - isRetainOffline: 是否让后台在对方不在线时保存这条离线消息,等到对方上线后再推送给对方。默认为 `true`。 672 | - isCustomNotificationEnabled: 是否开启自定义接收方通知栏功能,设置为 `true` 后可设置下面的 `notificationTitle` 和 `notificationText`。默认未设置。 673 | - notificationTitle: 设置此条消息在接收方通知栏所展示通知的标题。 674 | - notificationText: 设置此条消息在接收方通知栏所展示通知的内容。 675 | 676 | ### sendVoiceMessage 677 | 678 | 发送语音消息,在收到消息时 SDK 默认会自动下载语音文件,如果下载失败(即语音消息文件路径为空),可调用 `downloadVoiceFile` 手动下载。 679 | 680 | #### 示例 681 | 682 | ```dart 683 | jmessage.sendVoiceMessage( 684 | type: msg.from.targetType, 685 | path: msg.path, 686 | ) 687 | ``` 688 | 689 | #### 参数说明 690 | 691 | - type: 会话类型。可以为 (JMSingle | JMGroup | JMChatRoom)。 692 | - path: 本地音频文件的绝对路径。 693 | - extras (Map): 自定义键值对,key 、value 必须为字符串类型。 694 | - sendingOptions: 消息发送配置参数。支持的属性: 695 | - isShowNotification: 接收方是否针对此次消息发送展示通知栏通知。默认为 `true`。 696 | - isRetainOffline: 是否让后台在对方不在线时保存这条离线消息,等到对方上线后再推送给对方。默认为 `true`。 697 | - isCustomNotificationEnabled: 是否开启自定义接收方通知栏功能,设置为 `true` 后可设置下面的 `notificationTitle` 和 `notificationText`。默认未设置。 698 | - notificationTitle: 设置此条消息在接收方通知栏所展示通知的标题。 699 | - notificationText: 设置此条消息在接收方通知栏所展示通知的内容。 700 | 701 | ### sendCustomMessage 702 | 703 | 发送自定义消息。 704 | 705 | #### 示例 706 | 707 | ```dart 708 | JMCustomMessage msg = await JMessage.sendCustomMessage( 709 | type: kMockGroup, 710 | customObject: {'customKey1': 'customValue1'} 711 | ); 712 | ``` 713 | 714 | #### 参数说明 715 | 716 | - type: 会话类型。可以为 (JMSingle | JMGroup | JMChatRoom)。 717 | - customObject: 自定义键值对,`value` 必须为字符串类型。 718 | - sendingOptions: 消息发送配置参数。支持的属性: 719 | - isShowNotification: 接收方是否针对此次消息发送展示通知栏通知。默认为 `true`。 720 | - isRetainOffline: 是否让后台在对方不在线时保存这条离线消息,等到对方上线后再推送给对方。默认为 `true`。 721 | - isCustomNotificationEnabled: 是否开启自定义接收方通知栏功能,设置为 `true` 后可设置下面的 `notificationTitle` 和 `notificationText`。默认未设置。 722 | - notificationTitle: 设置此条消息在接收方通知栏所展示通知的标题。 723 | - notificationText: 设置此条消息在接收方通知栏所展示通知的内容。 724 | 725 | ### sendLocationMessage 726 | 727 | 发送地理位置消息,通常需要配合地图插件使用。 728 | 729 | #### 示例 730 | 731 | ```dart 732 | JMLocationMessage msg = await jmessage.sendVoiceMessage( 733 | type: kMockUser, 734 | longitude: kmockgitude, 735 | latitude: kmocklatitude 736 | ) 737 | ``` 738 | 739 | #### 参数说明 740 | 741 | - type: 会话类型。可以为 (JMSingle | JMGroup | JMChatRoom)。 742 | - latitude: 纬度。 743 | - longitude: 经度。 744 | - scale: 地图缩放比例。 745 | - address: 详细地址。 746 | - extras: 自定义键值对,value 必须为字符串类型。 747 | - sendingOptions: 消息发送配置参数。支持的属性: 748 | - isShowNotification: 接收方是否针对此次消息发送展示通知栏通知。默认为 `true`。 749 | - isRetainOffline: 是否让后台在对方不在线时保存这条离线消息,等到对方上线后再推送给对方。默认为 `true`。 750 | - isCustomNotificationEnabled: 是否开启自定义接收方通知栏功能,设置为 `true` 后可设置下面的 `notificationTitle` 和 `notificationText`。默认未设置。 751 | - notificationTitle: 设置此条消息在接收方通知栏所展示通知的标题。 752 | - notificationText: 设置此条消息在接收方通知栏所展示通知的内容。 753 | 754 | ### sendFileMessage 755 | 756 | 发送文件消息。对方在收到文件消息时 SDK 不会自动下载,下载文件需手动调用 `downloadFile` 方法。 757 | 758 | #### 示例 759 | 760 | ```dart 761 | JMFileMessage msg = await jmessage.sendFileMessage( 762 | type: kMockUser, 763 | path: kMockFilePath, 764 | ); 765 | ``` 766 | 767 | #### 参数说明 768 | 769 | - type: 会话类型。可以为 (JMSingle | JMGroup | JMChatRoom)。 770 | - path: 本地文件的绝对路径。 771 | - extras: 自定义键值对,value 必须为字符串类型。 772 | - sendingOptions: 消息发送配置参数。支持的属性: 773 | - isShowNotification: 接收方是否针对此次消息发送展示通知栏通知。默认为 `true`。 774 | - isRetainOffline: 是否让后台在对方不在线时保存这条离线消息,等到对方上线后再推送给对方。默认为 `true`。 775 | - isCustomNotificationEnabled: 是否开启自定义接收方通知栏功能,设置为 `true` 后可设置下面的 `notificationTitle` 和 `notificationText`。默认未设置。 776 | - notificationTitle: 设置此条消息在接收方通知栏所展示通知的标题。 777 | - notificationText: 设置此条消息在接收方通知栏所展示通知的内容。 778 | 779 | ### retractMessage 780 | 781 | 消息撤回。调用后被撤回方会收到一条 `retractMessage` 事件。并且双方的消息内容将变为不可见。 782 | 783 | #### 示例 784 | 785 | ```dart 786 | JMessage.retractMessage( 787 | type: kMockUser, 788 | messageId: 'target_msg_id' 789 | ); 790 | ``` 791 | 792 | #### 参数说明 793 | 794 | - type: 会话类型。可以为 (JMSingle | JMGroup)。 795 | - messageId: 要撤回的消息 id。 796 | 797 | ### getHistoryMessages 798 | 799 | 从最新的消息开始获取历史消息。 800 | 801 | #### 示例 802 | 803 | ```dart 804 | JMessage.getHistoryMessages( 805 | type: kMockUser, 806 | from: 0, 807 | limit: 10, 808 | isDescend: false 809 | ); 810 | ``` 811 | 812 | #### 参数说明 813 | 814 | - type: 会话类型。可以为 (JMSingle | JMGroup)。 815 | 816 | - from: 第一条消息对应的下标,起始为 0。 817 | 818 | - limit: 消息数。当 from = 0 并且 limit = -1 时,返回所有的历史消息。 819 | 820 | - isDescend: 是否降序(消息时间戳从大到小排序),默认为 false。 821 | ​ 822 | 823 | ### downloadOriginalImage 824 | 825 | 下载图片消息原图。如果已经下载,会直接返回本地文件路径,不会重复下载。 826 | 827 | #### 示例 828 | 829 | ```dart 830 | JMessage.downloadOriginalImage( 831 | target: kMockUser, 832 | messageId: 'target_msg_id' 833 | }); 834 | ``` 835 | 836 | #### 参数说明 837 | 838 | - type: 会话类型。可以为 (JMSingle | JMGroup | JMChatRoom)。 839 | - messageId: 图片消息 id。 840 | 841 | ### downloadThumbImage 842 | 843 | 下载图片消息缩略图。如果已经下载,会直接返回本地文件路径,不会重复下载。 844 | 845 | #### 示例 846 | 847 | ```dart 848 | Map resJson = await JMessage.downloadThumbImage( 849 | target: kMockUser, 850 | messageId: 'target_msg_id' 851 | }); 852 | 853 | resJson == { 854 | 'messageId': resJson['messageId'], 855 | 'filePath': resJson['filePath'] 856 | } 857 | ``` 858 | 859 | #### 参数说明 860 | 861 | - type: 会话类型。可以为 (JMSingle | JMGroup | JMChatRoom)。 862 | - username: 对方用户的用户名。当 `type` 为 'single' 时,`username` 为必填。 863 | - appKey: 对方用户所属应用的 AppKey。如果不填,默认为当前应用。 864 | - groupId: 对象群组 id。当 `type` 为 'group' 时,`groupId` 为必填。 865 | - messageId: 图片消息 id。 866 | 867 | ### downloadVoiceFile 868 | 869 | 下载语音文件。如果已经下载,会直接返回本地文件路径,不会重复下载。 870 | 871 | ### 示例 872 | 873 | ```dart 874 | Map resJson = await JMessage.downloadVoiceFile( 875 | type: kMockUser, 876 | messageId: 'target_msg_id' 877 | ); 878 | resJson == { 879 | 'messageId': resJson['messageId'], 880 | 'filePath': resJson['filePath'] 881 | } 882 | ``` 883 | 884 | #### 参数说明 885 | 886 | - type: 会话类型。可以为 (JMSingle | JMGroup)。 887 | - messageId: 语音消息 id。 888 | 889 | ### downloadFile 890 | 891 | 下载文件。如果已经下载,会直接返回本地文件路径,不会重复下载。 892 | 893 | #### 示例 894 | 895 | ```dart 896 | Map resJson = await JMessage.downloadFile( 897 | type: kMockUser, 898 | messageId: 'target_msg_id' 899 | ); 900 | 901 | resJson == { 902 | 'messageId': resJson['messageId'], 903 | 'filePath': resJson['filePath'] 904 | } 905 | ``` 906 | 907 | #### 参数说明 908 | 909 | - type: 会话类型。可以为 (JMSingle | JMGroup)。 910 | - messageId: 文件消息 id。 911 | 912 | ## 会话 913 | 914 | ### createConversation 915 | 916 | 创建会话。 917 | 918 | #### 示例 919 | 920 | ```dart 921 | JMConversationInfo conversation = await JMessage.createConversation( 922 | target:kMockUser 923 | ); 924 | ``` 925 | 926 | #### 参数说明 927 | 928 | - target: 会话类型。可以为 (JMSingle | JMGroup | JMChatRoom)。 929 | 930 | ### deleteConversation 931 | 932 | 删除聊天会话,同时也会删除本地聊天记录。 933 | 934 | #### 示例 935 | 936 | ```dart 937 | await JMessage.deleteConversation( 938 | target:kMockUser 939 | ); 940 | ``` 941 | 942 | #### 参数说明 943 | 944 | - target: 会话类型。可以为 (JMSingle | JMGroup | JMChatRoom)。 945 | 946 | ### enterConversation 947 | 948 | **(Android only)** 进入聊天会话。当调用后,该聊天会话的消息将不再显示通知。 949 | 950 | iOS 默认应用在前台时,就不会显示通知。 951 | 952 | #### 示例 953 | 954 | ```dart 955 | await JMessage.enterConversation( 956 | target:kMockUser 957 | ); 958 | ``` 959 | 960 | #### 参数说明 961 | 962 | - target: 会话类型。可以为 (JMSingle | JMGroup | JMChatRoom)。 963 | 964 | ### exitConversation 965 | 966 | **(Android only)** 退出当前聊天会话。调用后,聊天会话之后的相关消息通知将会被触发。 967 | 968 | #### 示例 969 | 970 | ```dart 971 | await JMessage.exitConversation( 972 | target:kMockUser 973 | ); 974 | ``` 975 | 976 | ### getConversation 977 | 978 | 获取聊天会话对象。 979 | 980 | #### 示例 981 | 982 | ```dart 983 | JMConversationInfo conversation = await jmessage.getConversation(target: kMockUser); 984 | ``` 985 | 986 | #### 参数说明 987 | 988 | - target: 会话类型。可以为 (JMSingle | JMGroup | JMChatRoom)。 989 | 990 | ### getConversations 991 | 992 | 从本地数据库获取会话列表。默认按照会话的最后一条消息时间降序排列。 993 | 994 | #### 示例 995 | 996 | ```dart 997 | List conversations = await JMessage.getConversations(); 998 | ``` 999 | 1000 | ### getAllUnreadCount 1001 | 1002 | 当前用户所有会话的未读消息总数 1003 | 1004 | - ⚠️ 截止jmessage-sdk-2.6.1 返回的数量为会话列表的未读总数即包括了被移除的群组、好友的未读. 1005 | 1006 | #### 示例 1007 | 1008 | ```dart 1009 | num unreadCount = await JMessage.getAllUnreadCount(); 1010 | ``` 1011 | 1012 | #### 1013 | 1014 | ### resetUnreadMessageCount 1015 | 1016 | 重置会话的未读消息数。 1017 | 1018 | #### 示例 1019 | 1020 | ```dart 1021 | await JMessage.resetUnreadMessageCount( 1022 | target: kMockuser 1023 | ); 1024 | ``` 1025 | 1026 | #### 参数说明 1027 | 1028 | - target: 会话类型。可以为 (JMSingle | JMGroup | JMChatRoom)。 1029 | 1030 | ## 聊天室 1031 | 1032 | #### 注意: 聊天室相关 api 功能还不完整,建议先不要添加相关功能。 1033 | 1034 | ### enterChatRoom 1035 | 1036 | 进入聊天室,进入后才能收到聊天室信息及发言。 1037 | 1038 | #### 示例 1039 | 1040 | ```dart 1041 | await JMessage.enterChatRoom({ roomId: 'Example_RoomId_1'}, 1042 | (conversation) => { // 进入聊天室,会自动创建并返回该聊天室会话信息。 1043 | // do something. 1044 | 1045 | }, (error) => { 1046 | var code = error.code 1047 | var desc = error.description 1048 | }) 1049 | ``` 1050 | 1051 | #### 参数说明 1052 | 1053 | - roomId:要进入的聊天室的 id。 1054 | 1055 | ### exitChatRoom 1056 | 1057 | 离开指定聊天室。 1058 | 1059 | #### 示例 1060 | 1061 | ```dart 1062 | await JMessage.leaveChatRoom({ roomId: 'Example_RoomId_1'}, 1063 | () => { 1064 | // do something. 1065 | 1066 | }, (error) => { 1067 | var code = error.code 1068 | var desc = error.description 1069 | }) 1070 | ``` 1071 | 1072 | #### 参数说明 1073 | 1074 | - roomId:要离开的聊天室的 id。 1075 | 1076 | ### getChatRoomConversationList 1077 | 1078 | 从本地获取用户的聊天室会话列表,没有则返回为空的列表。 1079 | 1080 | #### 示例 1081 | 1082 | ```dart 1083 | List conversations = await JMessage.getChatRoomConversationList(); 1084 | ``` 1085 | 1086 | 1087 | 1088 | ## 好友 1089 | 1090 | JMessage 好友模块仅实现对用户好友关系的托管,以及相关好友请求的发送与接收。 1091 | 除此之外更多的功能,比如仅允许好友间聊天需要开发者自行实现。 1092 | 1093 | ### sendInvitationRequest 1094 | 1095 | 发送添加好友请求,调用后对方会收到 [好友事件](#addcontactnotifylistener) 事件。 1096 | 1097 | #### 示例 1098 | 1099 | ```dart 1100 | JMessage.sendInvitationRequest( 1101 | username: 'username', 1102 | appKey: 'appKey', 1103 | reason: '请求添加好友' 1104 | ); 1105 | ``` 1106 | 1107 | #### 参数说明 1108 | 1109 | - username: 对方用户的用户名。 1110 | - appKey: 对方用户所属应用的 AppKey,如果为空则默认为当前应用。 1111 | - reason: 申请理由。 1112 | 1113 | ### acceptInvitation 1114 | 1115 | 接受申请好友请求,调用后对方会收到 [好友事件](#addcontactnotifylistener) 事件。 1116 | 1117 | #### 示例 1118 | 1119 | ```dart 1120 | await JMessage.acceptInvitation( 1121 | username: 'username', 1122 | appKey: 'appKey' 1123 | ); 1124 | ``` 1125 | 1126 | #### 参数说明 1127 | 1128 | - username: 申请发送用户的用户名。 1129 | - appKey: 申请发送用户所在应用的 AppKey。 1130 | 1131 | ### declineInvitation 1132 | 1133 | 拒绝申请好友请求,调用成功后对方会收到 [好友事件](#addcontactnotifylistener) 事件。 1134 | 1135 | #### 示例 1136 | 1137 | ```dart 1138 | await JMessage.declineInvitation( 1139 | username: 'username', 1140 | appKey: 'appKey', 1141 | reason: '拒绝理由' 1142 | ); 1143 | ``` 1144 | 1145 | #### 参数说明 1146 | 1147 | - username: 申请发送用户的用户名。 1148 | - appKey: 申请发送用户所在应用的 AppKey。 1149 | - reason: 拒绝理由。长度要求为 0 ~ 250 Byte。 1150 | 1151 | ### getFriends 1152 | 1153 | 获取好友列表。 1154 | 1155 | #### 示例 1156 | 1157 | ```dart 1158 | List users = await JMessage.getFriends(); 1159 | ``` 1160 | 1161 | ### removeFromFriendList 1162 | 1163 | 删除好友,调用成功后对方会收到 [好友事件](#addcontactnotifylistener) 事件。 1164 | 1165 | #### 示例 1166 | 1167 | ```dart 1168 | await JMessage.removeFromFriendList( 1169 | username: 'username', 1170 | appKey: 'appKey' 1171 | ); 1172 | ``` 1173 | 1174 | ### updateFriendNoteName 1175 | 1176 | 更新好友备注名。 1177 | 1178 | #### 示例 1179 | 1180 | ```dart 1181 | await JMessage.updateFriendNoteName( 1182 | username: 'username', 1183 | appKey: 'appKey', 1184 | noteName: 'noteName' 1185 | ); 1186 | ``` 1187 | 1188 | #### 参数说明 1189 | 1190 | - username: 好友的用户名。 1191 | - appKey: 好友所属应用的 AppKey,如果为空默认为当前应用。 1192 | - noteName: 备注名。不支持 "\n" 和 "\r" 字符,长度要求为 0 ~ 64 Byte。 1193 | 1194 | ### updateFriendNoteText 1195 | 1196 | 更新用户备注信息。 1197 | 1198 | #### 示例 1199 | 1200 | ```dart 1201 | await JMessage.updateFriendNoteText( 1202 | username: 'username', 1203 | appKey: 'appKey', 1204 | noteText: 'noteName' 1205 | ) 1206 | ``` 1207 | 1208 | #### 参数说明 1209 | 1210 | - username: 好友的用户名。 1211 | - appKey: 好友所属应用的 AppKey,如果为空默认为当前应用。 1212 | - noteText: 备注名。长度要求为 0 ~ 250 Byte。 1213 | 1214 | ## 事件监听 1215 | 1216 | ### 消息事件 1217 | 1218 | #### addReceiveMessageListener 1219 | 1220 | 添加消息事件的监听。 1221 | 1222 | ##### 示例 1223 | 1224 | ```dart 1225 | 1226 | JMessage.addReceiveMessageListener(listener) // 添加监听 1227 | JMessage.removeReceiveMessageListener(listener) // 移除监听 1228 | ``` 1229 | 1230 | #### addReceiveChatRoomMsgListener 1231 | 1232 | 添加聊天室消息事件的监听。 1233 | 1234 | ##### 示例 1235 | 1236 | ```dart 1237 | JMessage.addReceiveChatRoomMsgListene(listener) // 添加监听 1238 | JMessage.removeReceiveChatRoomMsgListener(listener) // 移除监听 1239 | ``` 1240 | 1241 | #### addSyncOfflineMessageListener 1242 | 1243 | 同步离线消息事件监听。 1244 | 1245 | ##### 示例 1246 | 1247 | ```dart 1248 | JMessage.addSyncOfflineMessageListener(listener) // 添加监听 1249 | JMessage.removeSyncOfflineMessageListener(listener) // 移除监听 1250 | ``` 1251 | 1252 | ##### 回调参数 1253 | 1254 | - callbackResult 1255 | - conversation:离线消息所在的会话 1256 | - messageArray:指定会话中的离线消息 1257 | 1258 | #### addSyncRoamingMessageListener 1259 | 1260 | 同步漫游消息事件监听。 1261 | 1262 | ##### 示例 1263 | 1264 | ```dart 1265 | JMessage.addSyncRoamingMessageListener(listener) // 添加监听 1266 | JMessage.removeSyncRoamingMessageListener(listener) // 移除监听 1267 | ``` 1268 | 1269 | ##### 回调参数 1270 | 1271 | - callbackResult 1272 | - conversation:漫游消息所在的会话。 1273 | 1274 | #### addMessageRetractListener 1275 | 1276 | 消息撤回事件监听。 1277 | 1278 | ##### 示例 1279 | 1280 | ```dart 1281 | JMessage.addMessageRetractListener(listener) // 添加监听 1282 | JMessage.removeMessageRetractListener(listener) // 移除监听 1283 | ``` 1284 | 1285 | ##### 回调参数 1286 | 1287 | - event 1288 | - conversation: 会话对象 1289 | - retractedMessage:被撤回的消息对象 1290 | 1291 | #### addClickMessageNotificationListener 1292 | 1293 | 点击消息通知回调(Android Only,iOS 端可以使用 jpush-react-native 插件的,监听点击推送的事件)。 1294 | 1295 | ##### 示例 1296 | 1297 | ```dart 1298 | JMessage.addClickMessageNotificationListener(listener) // 添加监听 1299 | JMessage.removeClickMessageNotificationListener(listener) // 移除监听 1300 | ``` 1301 | 1302 | ##### 回调参数 1303 | 1304 | - message: 可以是 JMTextMessage | JMVoiceMessage | JMImageMessage | JMFileMessage | JMEventMessage | JMCustomMessage; 1305 | 1306 | ### 好友事件 1307 | 1308 | #### addContactNotifyListener 1309 | 1310 | 好友相关通知事件。 1311 | 1312 | ##### 示例 1313 | 1314 | ```dart 1315 | JMessage.addContactNotifyListener(listener) // 添加监听 1316 | JMessage.removeContactNotifyListener(listener) // 移除监听 1317 | ``` 1318 | 1319 | ##### 回调参数 1320 | 1321 | - event 1322 | - type:'invite_received' / 'invite_accepted' / 'invite_declined' / 'contact_deleted' 1323 | - reason:事件发生的理由,该字段由对方发起请求时所填,对方如果未填则返回默认字符串。 1324 | - fromUsername: 事件发送者的 username。 1325 | - fromUserAppKey: 事件发送者的 AppKey。 1326 | 1327 | ### 登录状态事件 1328 | 1329 | #### addLoginStateChangedListener 1330 | 1331 | 登录状态变更事件,例如在其他设备登录把当前设备挤出,会触发这个事件。 1332 | 1333 | ##### 示例 1334 | 1335 | ```dart 1336 | JMessage.addLoginStateChangedListener(listener) // 添加监听 1337 | JMessage.removeMessageRetractListener(listener) // 移除监听 1338 | ``` 1339 | 1340 | ##### 回调参数 1341 | 1342 | - type: JMLoginStateChangedType。 1343 | 1344 | ### 群组事件 1345 | 1346 | #### addReceiveApplyJoinGroupApprovalListener 1347 | 1348 | 监听接收入群申请事件 1349 | 1350 | ##### 示例 1351 | 1352 | ```dart 1353 | 1354 | JMessage.addReceiveApplyJoinGroupApprovalListener(listener) // 添加监听 1355 | JMessage.removeReceiveApplyJoinGroupApprovalListener(listener) // 移除监听 1356 | ``` 1357 | 1358 | ##### 回调参数说明 1359 | 1360 | - event: JMReceiveApplyJoinGroupApprovalEvent 1361 | - eventId (string):消息 id。 1362 | - groupId (string):申请入群的 groudId。 1363 | - isInitiativeApply (boolean):是否是用户主动申请入群,YES:主动申请加入,NO:被邀请加入 1364 | - sendApplyUser (JMUserInfo):发送申请的用户 1365 | - reason (string):入群原因 1366 | 1367 | #### addReceiveGroupAdminRejectListener 1368 | 1369 | 监听管理员拒绝入群申请事件 1370 | 1371 | ##### 示例 1372 | 1373 | ```dart 1374 | JMessage.addReceiveGroupAdminRejectListener(listener) // 添加监听 1375 | JMessage.removeReceiveGroupAdminRejectListener(listener) // 移除监听 1376 | ``` 1377 | 1378 | ##### 回调参数说明 1379 | 1380 | - event: JMReceiveGroupAdminRejectEvent 1381 | - eventId (string): 消息 id。 1382 | - rejectReason (string): 拒绝原因。 1383 | - groupManager (JMUserInfo): 操作的管理员 1384 | 1385 | #### addReceiveGroupAdminApprovalListener 1386 | 1387 | 监听管理员同意入群申请事件 1388 | 1389 | ##### 示例 1390 | 1391 | ```dart 1392 | JMessage.addReceiveGroupAdminApprovalListener(listener) // 添加监听 1393 | JMessage.removeReceiveGroupAdminApprovalListener(listener) // 移除监听 1394 | ``` 1395 | 1396 | ##### 回调参数说明 1397 | 1398 | - event: JMReceiveGroupAdminApprovalEvent 1399 | - isAgreeApply (boolean): 管理员是否同意申请,YES:同意,NO:拒绝. 1400 | - applyEventID (string): 申请入群事件的事件 id. 1401 | - groupId (string): 群 gid. 1402 | - groupAdmin (JMGroupInfo): 操作的管理员. 1403 | - users [JMUserInfo]: 申请或被邀请加入群的用户,即:实际入群的用户 1404 | -------------------------------------------------------------------------------- /example/.flutter-plugins-dependencies: -------------------------------------------------------------------------------- 1 | {"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"image_picker","path":"D:\\\\Workspace\\\\android\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.flutter-io.cn\\\\image_picker-0.7.5+2\\\\","dependencies":[]},{"name":"jmessage_flutter","path":"D:\\\\Workspace\\\\flutter\\\\jmessage-flutter-plugin\\\\","dependencies":[]},{"name":"modal_progress_hud_nsn","path":"D:\\\\Workspace\\\\android\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.flutter-io.cn\\\\modal_progress_hud_nsn-0.1.0-nullsafety-1\\\\","dependencies":[]},{"name":"video_thumbnail","path":"D:\\\\Workspace\\\\android\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.flutter-io.cn\\\\video_thumbnail-0.3.3\\\\","dependencies":[]}],"android":[{"name":"flutter_plugin_android_lifecycle","path":"D:\\\\Workspace\\\\android\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.flutter-io.cn\\\\flutter_plugin_android_lifecycle-2.0.1\\\\","dependencies":[]},{"name":"image_picker","path":"D:\\\\Workspace\\\\android\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.flutter-io.cn\\\\image_picker-0.7.5+2\\\\","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"jmessage_flutter","path":"D:\\\\Workspace\\\\flutter\\\\jmessage-flutter-plugin\\\\","dependencies":[]},{"name":"modal_progress_hud_nsn","path":"D:\\\\Workspace\\\\android\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.flutter-io.cn\\\\modal_progress_hud_nsn-0.1.0-nullsafety-1\\\\","dependencies":[]},{"name":"video_thumbnail","path":"D:\\\\Workspace\\\\android\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.flutter-io.cn\\\\video_thumbnail-0.3.3\\\\","dependencies":[]}],"macos":[],"linux":[],"windows":[],"web":[{"name":"image_picker_for_web","path":"D:\\\\Workspace\\\\android\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.flutter-io.cn\\\\image_picker_for_web-2.0.0\\\\","dependencies":[]}]},"dependencyGraph":[{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"image_picker","dependencies":["flutter_plugin_android_lifecycle","image_picker_for_web"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"jmessage_flutter","dependencies":[]},{"name":"modal_progress_hud_nsn","dependencies":[]},{"name":"video_thumbnail","dependencies":[]}],"date_created":"2021-06-01 11:58:00.043626","version":"2.2.0"} -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.lock 4 | *.log 5 | *.pyc 6 | *.swp 7 | .DS_Store 8 | .atom/ 9 | .buildlog/ 10 | .history 11 | .svn/ 12 | 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # Visual Studio Code related 20 | .vscode/ 21 | 22 | # Flutter/Dart/Pub related 23 | **/doc/api/ 24 | .dart_tool/ 25 | .flutter-plugins 26 | .packages 27 | .pub-cache/ 28 | .pub/ 29 | build/ 30 | 31 | # Android related 32 | **/android/**/gradle-wrapper.jar 33 | **/android/.gradle 34 | **/android/captures/ 35 | **/android/gradlew 36 | **/android/gradlew.bat 37 | **/android/local.properties 38 | **/android/**/GeneratedPluginRegistrant.java 39 | 40 | # iOS/XCode related 41 | **/ios/**/*.mode1v3 42 | **/ios/**/*.mode2v3 43 | **/ios/**/*.moved-aside 44 | **/ios/**/*.pbxuser 45 | **/ios/**/*.perspectivev3 46 | **/ios/**/*sync/ 47 | **/ios/**/.sconsign.dblite 48 | **/ios/**/.tags* 49 | **/ios/**/.vagrant/ 50 | **/ios/**/DerivedData/ 51 | **/ios/**/Icon? 52 | **/ios/**/Pods/ 53 | **/ios/**/.symlinks/ 54 | **/ios/**/profile 55 | **/ios/**/xcuserdata 56 | **/ios/.generated/ 57 | **/ios/Flutter/App.framework 58 | **/ios/Flutter/Flutter.framework 59 | **/ios/Flutter/Generated.xcconfig 60 | **/ios/Flutter/app.flx 61 | **/ios/Flutter/app.zip 62 | **/ios/Flutter/flutter_assets/ 63 | **/ios/ServiceDefinitions.json 64 | **/ios/Runner/GeneratedPluginRegistrant.* 65 | 66 | # Exceptions to above rules. 67 | !**/ios/**/default.mode1v3 68 | !**/ios/**/default.mode2v3 69 | !**/ios/**/default.pbxuser 70 | !**/ios/**/default.perspectivev3 71 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 72 | -------------------------------------------------------------------------------- /example/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: f37c235c32fc15babe6dc7b7bc2ee4387e5ecf92 8 | channel: beta 9 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # jmessage_flutter_example 2 | 3 | Demonstrates how to use the jmessage_flutter plugin. 4 | 5 | ## Getting Started 6 | 7 | For help getting started with Flutter, view our online 8 | [documentation](https://flutter.io/). 9 | -------------------------------------------------------------------------------- /example/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 26 | 27 | android { 28 | compileSdkVersion 28 29 | 30 | lintOptions { 31 | disable 'InvalidPackage' 32 | } 33 | 34 | defaultConfig { 35 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 36 | applicationId "com.shikk.testJpush" 37 | minSdkVersion 17 38 | targetSdkVersion 28 39 | versionCode flutterVersionCode.toInteger() 40 | versionName flutterVersionName 41 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 42 | 43 | ndk { 44 | //选择要添加的对应 cpu 类型的 .so 库。 45 | abiFilters 'armeabi', 'armeabi-v7a', 'x86', 'x86_64', 'mips', 'mips64', 'arm64-v8a' 46 | // 还可以添加 47 | } 48 | 49 | manifestPlaceholders = [ 50 | JPUSH_PKGNAME : applicationId, 51 | JPUSH_APPKEY : "你自己应用的 AppKey", //极光 上注册的包名对应的 Appkey. 52 | JPUSH_CHANNEL : "developer-default", //暂时填写默认值即可. 53 | ] 54 | } 55 | 56 | buildTypes { 57 | release { 58 | // TODO: Add your own signing config for the release build. 59 | // Signing with the debug keys for now, so `flutter run --release` works. 60 | signingConfig signingConfigs.debug 61 | } 62 | } 63 | } 64 | 65 | flutter { 66 | source '../..' 67 | } 68 | 69 | dependencies { 70 | testImplementation 'junit:junit:4.12' 71 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 72 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 73 | } 74 | -------------------------------------------------------------------------------- /example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 8 | 9 | 10 | 15 | 19 | 26 | 30 | 34 | 39 | 43 | 44 | 45 | 46 | 47 | 48 | 50 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /example/android/app/src/main/java/com/jiguang/jmessageflutterexample/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.jiguang.jmessageflutterexample; 2 | 3 | import io.flutter.embedding.android.FlutterActivity; 4 | 5 | public class MainActivity extends FlutterActivity { 6 | } 7 | 8 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpush/jmessage-flutter-plugin/f19f8a0f7f1068362a0098314b22a1d6883ff2a5/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpush/jmessage-flutter-plugin/f19f8a0f7f1068362a0098314b22a1d6883ff2a5/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpush/jmessage-flutter-plugin/f19f8a0f7f1068362a0098314b22a1d6883ff2a5/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpush/jmessage-flutter-plugin/f19f8a0f7f1068362a0098314b22a1d6883ff2a5/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpush/jmessage-flutter-plugin/f19f8a0f7f1068362a0098314b22a1d6883ff2a5/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /example/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | google() 4 | jcenter() 5 | } 6 | 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:3.2.1' 9 | } 10 | } 11 | 12 | allprojects { 13 | repositories { 14 | google() 15 | jcenter() 16 | } 17 | } 18 | 19 | rootProject.buildDir = '../build' 20 | subprojects { 21 | project.buildDir = "${rootProject.buildDir}/${project.name}" 22 | } 23 | subprojects { 24 | project.evaluationDependsOn(':app') 25 | } 26 | 27 | task clean(type: Delete) { 28 | delete rootProject.buildDir 29 | } 30 | -------------------------------------------------------------------------------- /example/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.enableR8=true 3 | -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Oct 30 10:15:16 CST 2020 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip -------------------------------------------------------------------------------- /example/android/key.properties: -------------------------------------------------------------------------------- 1 | storePassword=123456 2 | keyPassword=123456 3 | keyAlias=key 4 | storeFile=/Users/raoxudong/Develop/android/key.jks -------------------------------------------------------------------------------- /example/android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() 4 | 5 | def plugins = new Properties() 6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') 7 | if (pluginsFile.exists()) { 8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } 9 | } 10 | 11 | plugins.each { name, path -> 12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() 13 | include ":$name" 14 | project(":$name").projectDir = pluginDirectory 15 | } 16 | -------------------------------------------------------------------------------- /example/assets/2.0x/nav_close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpush/jmessage-flutter-plugin/f19f8a0f7f1068362a0098314b22a1d6883ff2a5/example/assets/2.0x/nav_close.png -------------------------------------------------------------------------------- /example/assets/3.0x/nav_close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpush/jmessage-flutter-plugin/f19f8a0f7f1068362a0098314b22a1d6883ff2a5/example/assets/3.0x/nav_close.png -------------------------------------------------------------------------------- /example/assets/nav_close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpush/jmessage-flutter-plugin/f19f8a0f7f1068362a0098314b22a1d6883ff2a5/example/assets/nav_close.png -------------------------------------------------------------------------------- /example/ios/Flutter/.last_build_id: -------------------------------------------------------------------------------- 1 | fb2cd0472ffa0e4848752d33e0ab0ccb -------------------------------------------------------------------------------- /example/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 8.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /example/ios/Flutter/Flutter.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # NOTE: This podspec is NOT to be published. It is only used as a local source! 3 | # 4 | 5 | Pod::Spec.new do |s| 6 | s.name = 'Flutter' 7 | s.version = '1.0.0' 8 | s.summary = 'High-performance, high-fidelity mobile apps.' 9 | s.description = <<-DESC 10 | Flutter provides an easy and productive way to build and deploy high-performance mobile apps for Android and iOS. 11 | DESC 12 | s.homepage = 'https://flutter.io' 13 | s.license = { :type => 'MIT' } 14 | s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' } 15 | s.source = { :git => 'https://github.com/flutter/engine', :tag => s.version.to_s } 16 | s.ios.deployment_target = '8.0' 17 | s.vendored_frameworks = 'Flutter.framework' 18 | end 19 | -------------------------------------------------------------------------------- /example/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /example/ios/Flutter/flutter_export_environment.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # This is a generated file; do not edit or check into version control. 3 | export "FLUTTER_ROOT=D:\Workspace\android\flutter" 4 | export "FLUTTER_APPLICATION_PATH=D:\Workspace\flutter\jmessage-flutter-plugin\example" 5 | export "COCOAPODS_PARALLEL_CODE_SIGN=true" 6 | export "FLUTTER_TARGET=lib\main.dart" 7 | export "FLUTTER_BUILD_DIR=build" 8 | export "SYMROOT=${SOURCE_ROOT}/../build\ios" 9 | export "FLUTTER_BUILD_NAME=1.0.0" 10 | export "FLUTTER_BUILD_NUMBER=1" 11 | export "DART_OBFUSCATION=false" 12 | export "TRACK_WIDGET_CREATION=false" 13 | export "TREE_SHAKE_ICONS=false" 14 | export "PACKAGE_CONFIG=.packages" 15 | -------------------------------------------------------------------------------- /example/ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | def parse_KV_file(file, separator='=') 8 | file_abs_path = File.expand_path(file) 9 | if !File.exists? file_abs_path 10 | return []; 11 | end 12 | pods_ary = [] 13 | skip_line_start_symbols = ["#", "/"] 14 | File.foreach(file_abs_path) { |line| 15 | next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } 16 | plugin = line.split(pattern=separator) 17 | if plugin.length == 2 18 | podname = plugin[0].strip() 19 | path = plugin[1].strip() 20 | podpath = File.expand_path("#{path}", file_abs_path) 21 | pods_ary.push({:name => podname, :path => podpath}); 22 | else 23 | puts "Invalid plugin specification: #{line}" 24 | end 25 | } 26 | return pods_ary 27 | end 28 | 29 | target 'Runner' do 30 | # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock 31 | # referring to absolute paths on developers' machines. 32 | system('rm -rf .symlinks') 33 | system('mkdir -p .symlinks/plugins') 34 | 35 | # Flutter Pods 36 | generated_xcode_build_settings = parse_KV_file('./Flutter/Generated.xcconfig') 37 | if generated_xcode_build_settings.empty? 38 | puts "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter packages get is executed first." 39 | end 40 | generated_xcode_build_settings.map { |p| 41 | if p[:name] == 'FLUTTER_FRAMEWORK_DIR' 42 | symlink = File.join('.symlinks', 'flutter') 43 | File.symlink(File.dirname(p[:path]), symlink) 44 | pod 'Flutter', :path => File.join(symlink, File.basename(p[:path])) 45 | end 46 | } 47 | 48 | # Plugin Pods 49 | plugin_pods = parse_KV_file('../.flutter-plugins') 50 | plugin_pods.map { |p| 51 | symlink = File.join('.symlinks', 'plugins', p[:name]) 52 | File.symlink(p[:path], symlink) 53 | pod p[:name], :path => File.join(symlink, 'ios') 54 | } 55 | end 56 | 57 | post_install do |installer| 58 | installer.pods_project.targets.each do |target| 59 | target.build_configurations.each do |config| 60 | config.build_settings['ENABLE_BITCODE'] = 'NO' 61 | end 62 | end 63 | end 64 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 0421D6A4AECA46E06708D921 /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0D8562786885B6B17E6F1E79 /* libPods-Runner.a */; }; 11 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 12 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 13 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; }; 14 | 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; 15 | 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; 16 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 17 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 18 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 19 | /* End PBXBuildFile section */ 20 | 21 | /* Begin PBXCopyFilesBuildPhase section */ 22 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = { 23 | isa = PBXCopyFilesBuildPhase; 24 | buildActionMask = 2147483647; 25 | dstPath = ""; 26 | dstSubfolderSpec = 10; 27 | files = ( 28 | ); 29 | name = "Embed Frameworks"; 30 | runOnlyForDeploymentPostprocessing = 0; 31 | }; 32 | /* End PBXCopyFilesBuildPhase section */ 33 | 34 | /* Begin PBXFileReference section */ 35 | 08EFDA6E22E5A0760064D57C /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = ""; }; 36 | 0D8562786885B6B17E6F1E79 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 37 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 38 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 39 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 40 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 41 | 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 42 | 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 43 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 44 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 45 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 46 | 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 47 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 48 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 49 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 50 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 51 | CA73986AFFC3F39E1A9C5F66 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 52 | F4119DDD6425406B43A1B55A /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 53 | /* End PBXFileReference section */ 54 | 55 | /* Begin PBXFrameworksBuildPhase section */ 56 | 97C146EB1CF9000F007C117D /* Frameworks */ = { 57 | isa = PBXFrameworksBuildPhase; 58 | buildActionMask = 2147483647; 59 | files = ( 60 | 0421D6A4AECA46E06708D921 /* libPods-Runner.a in Frameworks */, 61 | ); 62 | runOnlyForDeploymentPostprocessing = 0; 63 | }; 64 | /* End PBXFrameworksBuildPhase section */ 65 | 66 | /* Begin PBXGroup section */ 67 | 3511FF9C175122F5F3E6EF69 /* Frameworks */ = { 68 | isa = PBXGroup; 69 | children = ( 70 | 0D8562786885B6B17E6F1E79 /* libPods-Runner.a */, 71 | ); 72 | name = Frameworks; 73 | sourceTree = ""; 74 | }; 75 | 9740EEB11CF90186004384FC /* Flutter */ = { 76 | isa = PBXGroup; 77 | children = ( 78 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 79 | 9740EEB21CF90195004384FC /* Debug.xcconfig */, 80 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 81 | 9740EEB31CF90195004384FC /* Generated.xcconfig */, 82 | ); 83 | name = Flutter; 84 | sourceTree = ""; 85 | }; 86 | 97C146E51CF9000F007C117D = { 87 | isa = PBXGroup; 88 | children = ( 89 | 9740EEB11CF90186004384FC /* Flutter */, 90 | 97C146F01CF9000F007C117D /* Runner */, 91 | 97C146EF1CF9000F007C117D /* Products */, 92 | BEE789AD141E349003616266 /* Pods */, 93 | 3511FF9C175122F5F3E6EF69 /* Frameworks */, 94 | ); 95 | sourceTree = ""; 96 | }; 97 | 97C146EF1CF9000F007C117D /* Products */ = { 98 | isa = PBXGroup; 99 | children = ( 100 | 97C146EE1CF9000F007C117D /* Runner.app */, 101 | ); 102 | name = Products; 103 | sourceTree = ""; 104 | }; 105 | 97C146F01CF9000F007C117D /* Runner */ = { 106 | isa = PBXGroup; 107 | children = ( 108 | 08EFDA6E22E5A0760064D57C /* Runner.entitlements */, 109 | 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */, 110 | 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */, 111 | 97C146FA1CF9000F007C117D /* Main.storyboard */, 112 | 97C146FD1CF9000F007C117D /* Assets.xcassets */, 113 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 114 | 97C147021CF9000F007C117D /* Info.plist */, 115 | 97C146F11CF9000F007C117D /* Supporting Files */, 116 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 117 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 118 | ); 119 | path = Runner; 120 | sourceTree = ""; 121 | }; 122 | 97C146F11CF9000F007C117D /* Supporting Files */ = { 123 | isa = PBXGroup; 124 | children = ( 125 | 97C146F21CF9000F007C117D /* main.m */, 126 | ); 127 | name = "Supporting Files"; 128 | sourceTree = ""; 129 | }; 130 | BEE789AD141E349003616266 /* Pods */ = { 131 | isa = PBXGroup; 132 | children = ( 133 | F4119DDD6425406B43A1B55A /* Pods-Runner.debug.xcconfig */, 134 | CA73986AFFC3F39E1A9C5F66 /* Pods-Runner.release.xcconfig */, 135 | ); 136 | name = Pods; 137 | sourceTree = ""; 138 | }; 139 | /* End PBXGroup section */ 140 | 141 | /* Begin PBXNativeTarget section */ 142 | 97C146ED1CF9000F007C117D /* Runner */ = { 143 | isa = PBXNativeTarget; 144 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; 145 | buildPhases = ( 146 | C6963D077F919AA39B9905A3 /* [CP] Check Pods Manifest.lock */, 147 | 9740EEB61CF901F6004384FC /* Run Script */, 148 | 97C146EA1CF9000F007C117D /* Sources */, 149 | 97C146EB1CF9000F007C117D /* Frameworks */, 150 | 97C146EC1CF9000F007C117D /* Resources */, 151 | 9705A1C41CF9048500538489 /* Embed Frameworks */, 152 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 153 | 03468A242FE0B80CF0AD9B45 /* [CP] Embed Pods Frameworks */, 154 | ); 155 | buildRules = ( 156 | ); 157 | dependencies = ( 158 | ); 159 | name = Runner; 160 | productName = Runner; 161 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */; 162 | productType = "com.apple.product-type.application"; 163 | }; 164 | /* End PBXNativeTarget section */ 165 | 166 | /* Begin PBXProject section */ 167 | 97C146E61CF9000F007C117D /* Project object */ = { 168 | isa = PBXProject; 169 | attributes = { 170 | LastUpgradeCheck = 0910; 171 | ORGANIZATIONNAME = "The Chromium Authors"; 172 | TargetAttributes = { 173 | 97C146ED1CF9000F007C117D = { 174 | CreatedOnToolsVersion = 7.3.1; 175 | DevelopmentTeam = 8X2A38Q9VD; 176 | ProvisioningStyle = Manual; 177 | SystemCapabilities = { 178 | com.apple.BackgroundModes = { 179 | enabled = 1; 180 | }; 181 | com.apple.Push = { 182 | enabled = 1; 183 | }; 184 | }; 185 | }; 186 | }; 187 | }; 188 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; 189 | compatibilityVersion = "Xcode 3.2"; 190 | developmentRegion = English; 191 | hasScannedForEncodings = 0; 192 | knownRegions = ( 193 | English, 194 | en, 195 | Base, 196 | ); 197 | mainGroup = 97C146E51CF9000F007C117D; 198 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */; 199 | projectDirPath = ""; 200 | projectRoot = ""; 201 | targets = ( 202 | 97C146ED1CF9000F007C117D /* Runner */, 203 | ); 204 | }; 205 | /* End PBXProject section */ 206 | 207 | /* Begin PBXResourcesBuildPhase section */ 208 | 97C146EC1CF9000F007C117D /* Resources */ = { 209 | isa = PBXResourcesBuildPhase; 210 | buildActionMask = 2147483647; 211 | files = ( 212 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 213 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 214 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */, 215 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 216 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, 217 | ); 218 | runOnlyForDeploymentPostprocessing = 0; 219 | }; 220 | /* End PBXResourcesBuildPhase section */ 221 | 222 | /* Begin PBXShellScriptBuildPhase section */ 223 | 03468A242FE0B80CF0AD9B45 /* [CP] Embed Pods Frameworks */ = { 224 | isa = PBXShellScriptBuildPhase; 225 | buildActionMask = 2147483647; 226 | files = ( 227 | ); 228 | inputPaths = ( 229 | "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", 230 | "${PODS_ROOT}/../.symlinks/flutter/ios/Flutter.framework", 231 | ); 232 | name = "[CP] Embed Pods Frameworks"; 233 | outputPaths = ( 234 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework", 235 | ); 236 | runOnlyForDeploymentPostprocessing = 0; 237 | shellPath = /bin/sh; 238 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; 239 | showEnvVarsInLog = 0; 240 | }; 241 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 242 | isa = PBXShellScriptBuildPhase; 243 | buildActionMask = 2147483647; 244 | files = ( 245 | ); 246 | inputPaths = ( 247 | ); 248 | name = "Thin Binary"; 249 | outputPaths = ( 250 | ); 251 | runOnlyForDeploymentPostprocessing = 0; 252 | shellPath = /bin/sh; 253 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; 254 | }; 255 | 9740EEB61CF901F6004384FC /* Run Script */ = { 256 | isa = PBXShellScriptBuildPhase; 257 | buildActionMask = 2147483647; 258 | files = ( 259 | ); 260 | inputPaths = ( 261 | ); 262 | name = "Run Script"; 263 | outputPaths = ( 264 | ); 265 | runOnlyForDeploymentPostprocessing = 0; 266 | shellPath = /bin/sh; 267 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build\n"; 268 | }; 269 | C6963D077F919AA39B9905A3 /* [CP] Check Pods Manifest.lock */ = { 270 | isa = PBXShellScriptBuildPhase; 271 | buildActionMask = 2147483647; 272 | files = ( 273 | ); 274 | inputPaths = ( 275 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 276 | "${PODS_ROOT}/Manifest.lock", 277 | ); 278 | name = "[CP] Check Pods Manifest.lock"; 279 | outputPaths = ( 280 | "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", 281 | ); 282 | runOnlyForDeploymentPostprocessing = 0; 283 | shellPath = /bin/sh; 284 | 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"; 285 | showEnvVarsInLog = 0; 286 | }; 287 | /* End PBXShellScriptBuildPhase section */ 288 | 289 | /* Begin PBXSourcesBuildPhase section */ 290 | 97C146EA1CF9000F007C117D /* Sources */ = { 291 | isa = PBXSourcesBuildPhase; 292 | buildActionMask = 2147483647; 293 | files = ( 294 | 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */, 295 | 97C146F31CF9000F007C117D /* main.m in Sources */, 296 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 297 | ); 298 | runOnlyForDeploymentPostprocessing = 0; 299 | }; 300 | /* End PBXSourcesBuildPhase section */ 301 | 302 | /* Begin PBXVariantGroup section */ 303 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = { 304 | isa = PBXVariantGroup; 305 | children = ( 306 | 97C146FB1CF9000F007C117D /* Base */, 307 | ); 308 | name = Main.storyboard; 309 | sourceTree = ""; 310 | }; 311 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { 312 | isa = PBXVariantGroup; 313 | children = ( 314 | 97C147001CF9000F007C117D /* Base */, 315 | ); 316 | name = LaunchScreen.storyboard; 317 | sourceTree = ""; 318 | }; 319 | /* End PBXVariantGroup section */ 320 | 321 | /* Begin XCBuildConfiguration section */ 322 | 97C147031CF9000F007C117D /* Debug */ = { 323 | isa = XCBuildConfiguration; 324 | buildSettings = { 325 | ALWAYS_SEARCH_USER_PATHS = NO; 326 | CLANG_ANALYZER_NONNULL = YES; 327 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 328 | CLANG_CXX_LIBRARY = "libc++"; 329 | CLANG_ENABLE_MODULES = YES; 330 | CLANG_ENABLE_OBJC_ARC = YES; 331 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 332 | CLANG_WARN_BOOL_CONVERSION = YES; 333 | CLANG_WARN_COMMA = YES; 334 | CLANG_WARN_CONSTANT_CONVERSION = YES; 335 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 336 | CLANG_WARN_EMPTY_BODY = YES; 337 | CLANG_WARN_ENUM_CONVERSION = YES; 338 | CLANG_WARN_INFINITE_RECURSION = YES; 339 | CLANG_WARN_INT_CONVERSION = YES; 340 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 341 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 342 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 343 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 344 | CLANG_WARN_STRICT_PROTOTYPES = YES; 345 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 346 | CLANG_WARN_UNREACHABLE_CODE = YES; 347 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 348 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 349 | COPY_PHASE_STRIP = NO; 350 | DEBUG_INFORMATION_FORMAT = dwarf; 351 | ENABLE_STRICT_OBJC_MSGSEND = YES; 352 | ENABLE_TESTABILITY = YES; 353 | GCC_C_LANGUAGE_STANDARD = gnu99; 354 | GCC_DYNAMIC_NO_PIC = NO; 355 | GCC_NO_COMMON_BLOCKS = YES; 356 | GCC_OPTIMIZATION_LEVEL = 0; 357 | GCC_PREPROCESSOR_DEFINITIONS = ( 358 | "DEBUG=1", 359 | "$(inherited)", 360 | ); 361 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 362 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 363 | GCC_WARN_UNDECLARED_SELECTOR = YES; 364 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 365 | GCC_WARN_UNUSED_FUNCTION = YES; 366 | GCC_WARN_UNUSED_VARIABLE = YES; 367 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 368 | MTL_ENABLE_DEBUG_INFO = YES; 369 | ONLY_ACTIVE_ARCH = YES; 370 | SDKROOT = iphoneos; 371 | TARGETED_DEVICE_FAMILY = "1,2"; 372 | }; 373 | name = Debug; 374 | }; 375 | 97C147041CF9000F007C117D /* Release */ = { 376 | isa = XCBuildConfiguration; 377 | buildSettings = { 378 | ALWAYS_SEARCH_USER_PATHS = NO; 379 | CLANG_ANALYZER_NONNULL = YES; 380 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 381 | CLANG_CXX_LIBRARY = "libc++"; 382 | CLANG_ENABLE_MODULES = YES; 383 | CLANG_ENABLE_OBJC_ARC = YES; 384 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 385 | CLANG_WARN_BOOL_CONVERSION = YES; 386 | CLANG_WARN_COMMA = YES; 387 | CLANG_WARN_CONSTANT_CONVERSION = YES; 388 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 389 | CLANG_WARN_EMPTY_BODY = YES; 390 | CLANG_WARN_ENUM_CONVERSION = YES; 391 | CLANG_WARN_INFINITE_RECURSION = YES; 392 | CLANG_WARN_INT_CONVERSION = YES; 393 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 394 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 395 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 396 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 397 | CLANG_WARN_STRICT_PROTOTYPES = YES; 398 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 399 | CLANG_WARN_UNREACHABLE_CODE = YES; 400 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 401 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 402 | COPY_PHASE_STRIP = NO; 403 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 404 | ENABLE_NS_ASSERTIONS = NO; 405 | ENABLE_STRICT_OBJC_MSGSEND = YES; 406 | GCC_C_LANGUAGE_STANDARD = gnu99; 407 | GCC_NO_COMMON_BLOCKS = YES; 408 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 409 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 410 | GCC_WARN_UNDECLARED_SELECTOR = YES; 411 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 412 | GCC_WARN_UNUSED_FUNCTION = YES; 413 | GCC_WARN_UNUSED_VARIABLE = YES; 414 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 415 | MTL_ENABLE_DEBUG_INFO = NO; 416 | SDKROOT = iphoneos; 417 | TARGETED_DEVICE_FAMILY = "1,2"; 418 | VALIDATE_PRODUCT = YES; 419 | }; 420 | name = Release; 421 | }; 422 | 97C147061CF9000F007C117D /* Debug */ = { 423 | isa = XCBuildConfiguration; 424 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 425 | buildSettings = { 426 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 427 | CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; 428 | CODE_SIGN_IDENTITY = "iPhone Developer"; 429 | CODE_SIGN_STYLE = Manual; 430 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 431 | DEVELOPMENT_TEAM = 8X2A38Q9VD; 432 | ENABLE_BITCODE = NO; 433 | FRAMEWORK_SEARCH_PATHS = ( 434 | "$(inherited)", 435 | "$(PROJECT_DIR)/Flutter", 436 | ); 437 | INFOPLIST_FILE = Runner/Info.plist; 438 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 439 | LIBRARY_SEARCH_PATHS = ( 440 | "$(inherited)", 441 | "$(PROJECT_DIR)/Flutter", 442 | ); 443 | PRODUCT_BUNDLE_IDENTIFIER = com.jmessage.sdk; 444 | PRODUCT_NAME = "$(TARGET_NAME)"; 445 | PROVISIONING_PROFILE_SPECIFIER = "com.jmessage.sdk-dev"; 446 | VERSIONING_SYSTEM = "apple-generic"; 447 | }; 448 | name = Debug; 449 | }; 450 | 97C147071CF9000F007C117D /* Release */ = { 451 | isa = XCBuildConfiguration; 452 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 453 | buildSettings = { 454 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 455 | CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; 456 | CODE_SIGN_IDENTITY = "iPhone Developer"; 457 | CODE_SIGN_STYLE = Manual; 458 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 459 | DEVELOPMENT_TEAM = 8X2A38Q9VD; 460 | ENABLE_BITCODE = NO; 461 | FRAMEWORK_SEARCH_PATHS = ( 462 | "$(inherited)", 463 | "$(PROJECT_DIR)/Flutter", 464 | ); 465 | INFOPLIST_FILE = Runner/Info.plist; 466 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 467 | LIBRARY_SEARCH_PATHS = ( 468 | "$(inherited)", 469 | "$(PROJECT_DIR)/Flutter", 470 | ); 471 | PRODUCT_BUNDLE_IDENTIFIER = com.jmessage.sdk; 472 | PRODUCT_NAME = "$(TARGET_NAME)"; 473 | PROVISIONING_PROFILE_SPECIFIER = "com.jmessage.sdk-dev"; 474 | VERSIONING_SYSTEM = "apple-generic"; 475 | }; 476 | name = Release; 477 | }; 478 | /* End XCBuildConfiguration section */ 479 | 480 | /* Begin XCConfigurationList section */ 481 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { 482 | isa = XCConfigurationList; 483 | buildConfigurations = ( 484 | 97C147031CF9000F007C117D /* Debug */, 485 | 97C147041CF9000F007C117D /* Release */, 486 | ); 487 | defaultConfigurationIsVisible = 0; 488 | defaultConfigurationName = Release; 489 | }; 490 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { 491 | isa = XCConfigurationList; 492 | buildConfigurations = ( 493 | 97C147061CF9000F007C117D /* Debug */, 494 | 97C147071CF9000F007C117D /* Release */, 495 | ); 496 | defaultConfigurationIsVisible = 0; 497 | defaultConfigurationName = Release; 498 | }; 499 | /* End XCConfigurationList section */ 500 | }; 501 | rootObject = 97C146E61CF9000F007C117D /* Project object */; 502 | } 503 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 56 | 58 | 64 | 65 | 66 | 67 | 68 | 69 | 75 | 77 | 83 | 84 | 85 | 86 | 88 | 89 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface AppDelegate : FlutterAppDelegate 5 | 6 | @end 7 | -------------------------------------------------------------------------------- /example/ios/Runner/AppDelegate.m: -------------------------------------------------------------------------------- 1 | #include "AppDelegate.h" 2 | #include "GeneratedPluginRegistrant.h" 3 | 4 | @implementation AppDelegate 5 | 6 | - (BOOL)application:(UIApplication *)application 7 | didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 8 | [GeneratedPluginRegistrant registerWithRegistry:self]; 9 | // Override point for customization after application launch. 10 | return [super application:application didFinishLaunchingWithOptions:launchOptions]; 11 | } 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpush/jmessage-flutter-plugin/f19f8a0f7f1068362a0098314b22a1d6883ff2a5/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpush/jmessage-flutter-plugin/f19f8a0f7f1068362a0098314b22a1d6883ff2a5/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpush/jmessage-flutter-plugin/f19f8a0f7f1068362a0098314b22a1d6883ff2a5/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpush/jmessage-flutter-plugin/f19f8a0f7f1068362a0098314b22a1d6883ff2a5/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpush/jmessage-flutter-plugin/f19f8a0f7f1068362a0098314b22a1d6883ff2a5/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpush/jmessage-flutter-plugin/f19f8a0f7f1068362a0098314b22a1d6883ff2a5/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpush/jmessage-flutter-plugin/f19f8a0f7f1068362a0098314b22a1d6883ff2a5/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpush/jmessage-flutter-plugin/f19f8a0f7f1068362a0098314b22a1d6883ff2a5/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpush/jmessage-flutter-plugin/f19f8a0f7f1068362a0098314b22a1d6883ff2a5/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpush/jmessage-flutter-plugin/f19f8a0f7f1068362a0098314b22a1d6883ff2a5/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpush/jmessage-flutter-plugin/f19f8a0f7f1068362a0098314b22a1d6883ff2a5/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpush/jmessage-flutter-plugin/f19f8a0f7f1068362a0098314b22a1d6883ff2a5/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpush/jmessage-flutter-plugin/f19f8a0f7f1068362a0098314b22a1d6883ff2a5/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpush/jmessage-flutter-plugin/f19f8a0f7f1068362a0098314b22a1d6883ff2a5/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpush/jmessage-flutter-plugin/f19f8a0f7f1068362a0098314b22a1d6883ff2a5/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpush/jmessage-flutter-plugin/f19f8a0f7f1068362a0098314b22a1d6883ff2a5/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpush/jmessage-flutter-plugin/f19f8a0f7f1068362a0098314b22a1d6883ff2a5/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpush/jmessage-flutter-plugin/f19f8a0f7f1068362a0098314b22a1d6883ff2a5/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSCameraUsageDescription 6 | demo 想要访问你的相机 7 | NSPhotoLibraryUsageDescription 8 | demo 想要访问你的相册 9 | CFBundleDevelopmentRegion 10 | en 11 | CFBundleExecutable 12 | $(EXECUTABLE_NAME) 13 | CFBundleIdentifier 14 | $(PRODUCT_BUNDLE_IDENTIFIER) 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | jmessage_flutter_example 19 | CFBundlePackageType 20 | APPL 21 | CFBundleShortVersionString 22 | $(FLUTTER_BUILD_NAME) 23 | CFBundleSignature 24 | ???? 25 | CFBundleVersion 26 | $(FLUTTER_BUILD_NUMBER) 27 | LSRequiresIPhoneOS 28 | 29 | UIBackgroundModes 30 | 31 | remote-notification 32 | 33 | UILaunchStoryboardName 34 | LaunchScreen 35 | UIMainStoryboardFile 36 | Main 37 | UISupportedInterfaceOrientations 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationLandscapeLeft 41 | UIInterfaceOrientationLandscapeRight 42 | 43 | UISupportedInterfaceOrientations~ipad 44 | 45 | UIInterfaceOrientationPortrait 46 | UIInterfaceOrientationPortraitUpsideDown 47 | UIInterfaceOrientationLandscapeLeft 48 | UIInterfaceOrientationLandscapeRight 49 | 50 | UIViewControllerBasedStatusBarAppearance 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /example/ios/Runner/Runner.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | aps-environment 6 | development 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import "AppDelegate.h" 4 | 5 | int main(int argc, char* argv[]) { 6 | @autoreleasepool { 7 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /example/lib/conversation_manage_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter/widgets.dart'; 3 | import 'package:jmessage_flutter/jmessage_flutter.dart'; 4 | import 'package:jmessage_flutter_example/main.dart'; 5 | import 'package:modal_progress_hud_nsn/modal_progress_hud_nsn.dart'; 6 | 7 | class ConversationManageView extends StatefulWidget { 8 | @override 9 | _ConversationManageViewState createState() => _ConversationManageViewState(); 10 | } 11 | 12 | class _ConversationManageViewState extends State { 13 | List dataList = []; 14 | bool _loading = false; 15 | String _result = "请选择需要操作的会话"; 16 | int selectIndex = -1; 17 | JMConversationInfo? selectConversationInfo; 18 | 19 | @override 20 | void initState() { 21 | super.initState(); 22 | 23 | demoGetConversationList(); 24 | } 25 | 26 | void addMessageEvent() async { 27 | jmessage.addReceiveMessageListener((msg) { 28 | //+ 29 | print('listener receive event - message : ${msg.toJson()}'); 30 | 31 | verifyMessage(msg); 32 | 33 | setState(() { 34 | _result = "【收到消息】${msg.toJson()}"; 35 | }); 36 | }); 37 | } 38 | 39 | @override 40 | Widget build(BuildContext context) { 41 | return new Scaffold( 42 | appBar: AppBar( 43 | title: new Text("会话列表", style: TextStyle(fontSize: 20)), 44 | leading: IconButton( 45 | icon: new Image.asset("assets/nav_close.png"), 46 | onPressed: () { 47 | Navigator.maybePop(context); 48 | }), 49 | ), 50 | body: ModalProgressHUD(inAsyncCall: _loading, child: _buildContentView()), 51 | ); 52 | } 53 | 54 | Widget _buildContentView() { 55 | return new Column( 56 | children: [ 57 | new Container( 58 | margin: EdgeInsets.fromLTRB(5, 5, 5, 0), 59 | color: Colors.brown, 60 | child: Text(_result), 61 | width: double.infinity, 62 | height: 120, 63 | ), 64 | new Row( 65 | mainAxisAlignment: MainAxisAlignment.start, 66 | children: [ 67 | new Text(" "), 68 | new CustomButton(title: "发送文本消息", onPressed: demoSendTextMessage), 69 | new Text(" "), 70 | new CustomButton(title: "获取历史消息", onPressed: demoGetHistorMessage), 71 | new Text(" "), 72 | new CustomButton( 73 | title: "刷新会话列表", 74 | onPressed: () { 75 | demoGetConversationList(); 76 | }), 77 | ], 78 | ), 79 | Expanded( 80 | child: new Container( 81 | color: Colors.grey, 82 | margin: EdgeInsets.fromLTRB(5, 5, 5, 5), 83 | child: new ListView.builder( 84 | itemCount: dataList.length * 2, 85 | itemBuilder: (context, i) { 86 | if (i.isOdd) return new Divider(); 87 | 88 | final index = i ~/ 2; 89 | 90 | return _buildRow(dataList[index], index); 91 | }), 92 | ), 93 | ), 94 | ], 95 | ); 96 | } 97 | 98 | Widget _buildRow(JMConversationInfo object, int index) { 99 | String title = 100 | "【${getStringFromEnum(object.conversationType)}】${object.title}"; 101 | 102 | return new Container( 103 | height: 60, 104 | child: new ListTile( 105 | //dense: true, 106 | //leading: CircleAvatar(backgroundImage: NetworkImage(url)), 107 | //trailing: Icon(Icons.keyboard_arrow_right), 108 | contentPadding: EdgeInsets.symmetric(horizontal: 10.0), 109 | //设置内容边距,默认是 16 110 | title: new Text(title), 111 | subtitle: new Text(object.latestMessage.toString()), 112 | selected: selectIndex == index, 113 | onTap: () { 114 | print("点击了第【${index + 1}】行"); 115 | setState(() { 116 | selectIndex = index; 117 | _result = "【选择的会话】\n ${object.toJson()}"; 118 | }); 119 | selectConversationInfo = object; 120 | }, 121 | ), 122 | ); 123 | } 124 | 125 | /// 获取公开群列表 126 | void demoGetConversationList() async { 127 | print("demoGetConversationList"); 128 | setState(() { 129 | selectIndex = -1; 130 | selectConversationInfo = null; 131 | _result = "请选择需要操作的会话"; 132 | _loading = true; 133 | }); 134 | 135 | List conversations = await jmessage.getConversations(); 136 | 137 | setState(() { 138 | _loading = false; 139 | dataList = conversations; 140 | }); 141 | 142 | for (JMConversationInfo info in conversations) { 143 | print('会话:${info.toJson()}'); 144 | } 145 | } 146 | 147 | int textIndex = 0; 148 | 149 | void demoSendTextMessage() async { 150 | print("demoSendTextMessage"); 151 | 152 | if (selectConversationInfo == null) { 153 | setState(() { 154 | _result = "请选着需要操作的会话"; 155 | }); 156 | return; 157 | } 158 | setState(() { 159 | _loading = true; 160 | }); 161 | 162 | JMTextMessage msg = await selectConversationInfo!.sendTextMessage( 163 | text: "send msg queen index $textIndex"); 164 | setState(() { 165 | _loading = false; 166 | _result = "【文本消息】${msg.toJson()}"; 167 | }); 168 | textIndex++; 169 | } 170 | 171 | // 历史消息 172 | void demoGetHistorMessage() async { 173 | print("demoGetHistorMessage"); 174 | 175 | if (selectConversationInfo == null) { 176 | setState(() { 177 | _result = "请选着需要操作的会话"; 178 | }); 179 | return; 180 | } 181 | 182 | setState(() { 183 | _loading = true; 184 | }); 185 | 186 | selectConversationInfo! 187 | .getHistoryMessages(from: 0, limit: 20) 188 | .then((msgList) { 189 | for (JMNormalMessage msg in msgList) { 190 | print("get conversation history msg : ${msg.toJson()}"); 191 | } 192 | 193 | setState(() { 194 | _loading = false; 195 | _result = "【消息列表】${msgList.toString()}"; 196 | }); 197 | }); 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /example/lib/group_manage_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter/widgets.dart'; 3 | import 'package:jmessage_flutter/jmessage_flutter.dart'; 4 | import 'package:jmessage_flutter_example/main.dart'; 5 | import 'package:modal_progress_hud_nsn/modal_progress_hud_nsn.dart'; 6 | 7 | class GroupManageView extends StatefulWidget { 8 | @override 9 | _GroupManageViewState createState() => _GroupManageViewState(); 10 | } 11 | 12 | class _GroupManageViewState extends State { 13 | List dataList = []; 14 | bool _loading = false; 15 | String _result = "选择需要操作的群组"; 16 | int selectIndex = -1; 17 | JMGroupInfo? selectedGroupInfo; 18 | 19 | var usernameTextEC1 = new TextEditingController(); 20 | 21 | @override 22 | Widget build(BuildContext context) { 23 | return new Scaffold( 24 | appBar: AppBar( 25 | title: new Text("群组列表", style: TextStyle(fontSize: 20)), 26 | leading: IconButton( 27 | icon: new Image.asset("assets/nav_close.png"), 28 | onPressed: () { 29 | Navigator.maybePop(context); 30 | }), 31 | ), 32 | body: ModalProgressHUD(inAsyncCall: _loading, child: _buildContentView()), 33 | ); 34 | } 35 | 36 | Widget _buildContentView() { 37 | return new Column( 38 | children: [ 39 | new Container( 40 | height: 100, 41 | child: new Row( 42 | children: [ 43 | Expanded( 44 | child: new Container( 45 | margin: EdgeInsets.fromLTRB(5, 5, 5, 0), 46 | color: Colors.brown, 47 | child: Text(_result), 48 | height: double.infinity, 49 | ), 50 | flex: 2, 51 | ), 52 | Expanded( 53 | child: new Column( 54 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 55 | children: [ 56 | new CustomButton(title: "私有群列表", onPressed: demoGetGidList), 57 | new CustomButton( 58 | title: "公开群列表", onPressed: demoGetPublicGroupInfos), 59 | ], 60 | ), 61 | flex: 1, 62 | ), 63 | ], 64 | ), 65 | ), 66 | new CustomTextField( 67 | hintText: "请输入username/group name", controller: usernameTextEC1), 68 | new Row( 69 | children: [ 70 | new Text(" "), 71 | new CustomButton(title: "成员列表", onPressed: demoGetMemberlist), 72 | new Text(" "), 73 | new CustomButton(title: "加入成员", onPressed: demoAddMember), 74 | new Text(" "), 75 | new CustomButton(title: "移除成员", onPressed: demoRemoveMember), 76 | new Text(" "), 77 | new CustomButton(title: "申请加入", onPressed: demoApplyJoinGroup), 78 | ], 79 | ), 80 | new Row( 81 | children: [ 82 | new Text(" "), 83 | new CustomButton( 84 | title: "创建公开群组", 85 | onPressed: () { 86 | demoCreateGroup(JMGroupType.public); 87 | }), 88 | new Text(" "), 89 | new CustomButton( 90 | title: "创建私有群组", 91 | onPressed: () { 92 | demoCreateGroup(JMGroupType.private); 93 | }), 94 | new Text(" "), 95 | new CustomButton(title: "创建群聊会话", onPressed: demoCreatConversation), 96 | ], 97 | ), 98 | Expanded( 99 | child: new Container( 100 | color: Colors.grey, 101 | margin: EdgeInsets.fromLTRB(5, 5, 5, 5), 102 | child: new ListView.builder( 103 | itemCount: dataList.length * 2, 104 | itemBuilder: (context, i) { 105 | if (i.isOdd) return new Divider(); 106 | final index = i ~/ 2; 107 | return _buildRow(dataList[index], index); 108 | }), 109 | ), 110 | ), 111 | ], 112 | ); 113 | } 114 | 115 | Widget _buildRow(dynamic object, int index) { 116 | String title = ""; 117 | String subTitle = ""; 118 | if (object is String) { 119 | title = "【私有群】gid: " + object; 120 | } else if (object is JMGroupInfo) { 121 | title = "【公开群】name: " + object.name; 122 | subTitle = " gid: " + object.id; 123 | } 124 | 125 | return new Container( 126 | height: 60, 127 | child: new ListTile( 128 | //dense: true, 129 | //leading: CircleAvatar(backgroundImage: NetworkImage(url)), 130 | //trailing: Icon(Icons.keyboard_arrow_right), 131 | contentPadding: EdgeInsets.symmetric(horizontal: 10.0), 132 | //设置内容边距,默认是 16 133 | title: new Text(title), 134 | subtitle: new Text(subTitle, style: TextStyle(fontSize: 14)), 135 | selected: selectIndex == index, 136 | onTap: () { 137 | print("点击了第【${index + 1}】行"); 138 | String? gid; 139 | if (object is String) { 140 | gid = object; 141 | } else if (object is JMGroupInfo) { 142 | gid = object.id; 143 | } 144 | demoGetGroupInfo(gid); 145 | setState(() { 146 | selectIndex = index; 147 | }); 148 | }, 149 | ), 150 | ); 151 | } 152 | 153 | void demoGetGroupInfo(String? gid) async { 154 | print("demoGetGroupInfo gid = $gid"); 155 | 156 | setState(() { 157 | _loading = true; 158 | }); 159 | 160 | JMGroupInfo groupInfo = await jmessage.getGroupInfo(id: gid); 161 | print("群信息:${groupInfo.toJson()}"); 162 | 163 | selectedGroupInfo = groupInfo; 164 | 165 | setState(() { 166 | _loading = false; 167 | _result = "【选择的群组信息】\n ${groupInfo.toJson()}"; 168 | }); 169 | } 170 | 171 | void demoGetMemberlist() async { 172 | print("demoGetMemberlist "); 173 | 174 | if (selectedGroupInfo == null) { 175 | setState(() { 176 | _result = "请选着需要操作的群组"; 177 | }); 178 | return; 179 | } 180 | 181 | setState(() { 182 | _loading = true; 183 | }); 184 | 185 | String gid = selectedGroupInfo!.id; 186 | List res = await jmessage.getGroupMembers(id: gid); 187 | print("群组【gid:$gid】的群成员列表:"); 188 | for (JMGroupMemberInfo member in res) { 189 | print("group member info : ${member.toJson()}"); 190 | } 191 | setState(() { 192 | _loading = false; 193 | _result = "【群成员信息】请查看控制台 log 输出"; 194 | }); 195 | } 196 | 197 | void demoAddMember() async { 198 | print("demoAddMember "); 199 | 200 | if (usernameTextEC1.text.isEmpty) { 201 | setState(() { 202 | _loading = false; 203 | _result = "【添加群成员】username 不能为空"; 204 | }); 205 | return; 206 | } 207 | if (selectedGroupInfo == null) { 208 | setState(() { 209 | _loading = false; 210 | _result = "【添加群成员】请选着需要操作的群组"; 211 | }); 212 | return; 213 | } 214 | String gid = selectedGroupInfo!.id; 215 | String username = usernameTextEC1.text; 216 | await jmessage.addGroupMembers(id: gid, usernameArray: [username]); 217 | setState(() { 218 | _loading = false; 219 | _result = "【添加群成员】操作完成"; 220 | }); 221 | } 222 | 223 | void demoRemoveMember() async { 224 | print("demoRemoveMember "); 225 | 226 | if (usernameTextEC1.text.isEmpty) { 227 | setState(() { 228 | _loading = false; 229 | _result = "【移除群成员】username 不能为空"; 230 | }); 231 | return; 232 | } 233 | if (selectedGroupInfo == null) { 234 | setState(() { 235 | _loading = false; 236 | _result = "【移除群成员】请选着需要操作的群组"; 237 | }); 238 | return; 239 | } 240 | String gid = selectedGroupInfo!.id; 241 | String username = usernameTextEC1.text; 242 | await jmessage.removeGroupMembers(id: gid, usernames: [username]); 243 | 244 | setState(() { 245 | _loading = false; 246 | _result = "【移除群成员】操作完成"; 247 | }); 248 | } 249 | 250 | void demoApplyJoinGroup() async { 251 | print("demoApplyJoinGroup"); 252 | 253 | setState(() { 254 | _loading = true; 255 | }); 256 | 257 | if (selectedGroupInfo == null) { 258 | setState(() { 259 | _loading = false; 260 | _result = "【申请加入群组】请选着需要操作的群组"; 261 | }); 262 | return; 263 | } 264 | 265 | if (selectedGroupInfo!.groupType == JMGroupType.private) { 266 | setState(() { 267 | _loading = false; 268 | _result = "【申请加入群组】该群为私有群,可直接加入"; 269 | }); 270 | return; 271 | } 272 | 273 | String gid = selectedGroupInfo!.id; 274 | await jmessage.applyJoinGroup(groupId: gid); 275 | 276 | setState(() { 277 | _loading = false; 278 | _result = "【申请加入群组】操作完成"; 279 | }); 280 | } 281 | 282 | /// 获取 我的群列表 283 | void demoGetGidList() async { 284 | print("demoGetGroupList"); 285 | 286 | reset(); 287 | 288 | setState(() { 289 | _loading = true; 290 | }); 291 | List list = await jmessage.getGroupIds(); 292 | setState(() { 293 | _loading = false; 294 | dataList = list; 295 | }); 296 | } 297 | 298 | /// 获取公开群列表 299 | void demoGetPublicGroupInfos() async { 300 | print("demoGetPublicGroupInfos"); 301 | 302 | reset(); 303 | setState(() { 304 | _loading = true; 305 | }); 306 | 307 | JMUserInfo? userInfo = await jmessage.getMyInfo(); 308 | String? appkey = userInfo!.appKey; 309 | 310 | List groupList = 311 | await jmessage.getPublicGroupInfos(appKey: appkey, start: 0, count: 20); 312 | setState(() { 313 | _loading = false; 314 | dataList = groupList; 315 | }); 316 | } 317 | 318 | void demoCreateGroup(JMGroupType type) async { 319 | print("demoCreateGroup" + usernameTextEC1.text); 320 | 321 | setState(() { 322 | _loading = true; 323 | }); 324 | 325 | if (usernameTextEC1.text.isEmpty) { 326 | setState(() { 327 | _loading = false; 328 | _result = "【创建公开群】group name 不能为空"; 329 | }); 330 | return; 331 | } 332 | String name = usernameTextEC1.text; 333 | String groupIdString = await jmessage.createGroup( 334 | groupType: type, name: name, desc: "$name-的群描述信息"); 335 | setState(() { 336 | _loading = false; 337 | _result = "【创建群组】创建成功,gid = $groupIdString"; 338 | }); 339 | } 340 | 341 | void demoCreatConversation() async { 342 | print("demoCreatConversation"); 343 | 344 | setState(() { 345 | _loading = true; 346 | }); 347 | 348 | if (selectedGroupInfo == null) { 349 | setState(() { 350 | _loading = false; 351 | _result = "【创建群聊会话】请选着需要操作的群组"; 352 | }); 353 | return; 354 | } 355 | 356 | String gid = selectedGroupInfo!.id; 357 | JMGroup group = JMGroup.fromJson({"groupId": gid}); 358 | JMConversationInfo conversationInfo = 359 | await jmessage.createConversation(target: group); 360 | 361 | setState(() { 362 | _loading = false; 363 | _result = "【创建群聊会话】 $conversationInfo"; 364 | }); 365 | } 366 | 367 | void reset() { 368 | setState(() { 369 | _result = "选择需要操作的群组"; 370 | selectIndex = -1; 371 | selectedGroupInfo = null; 372 | }); 373 | } 374 | } 375 | -------------------------------------------------------------------------------- /example/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: jmessage_flutter_example 2 | description: Demonstrates how to use the jmessage_flutter plugin. 3 | 4 | # The following defines the version and build number for your application. 5 | # A version number is three numbers separated by dots, like 1.2.43 6 | # followed by an optional build number separated by a +. 7 | # Both the version and the builder number may be overridden in flutter 8 | # build by specifying --build-name and --build-number, respectively. 9 | # Read more about versioning at semver.org. 10 | version: 1.0.0+1 11 | 12 | environment: 13 | sdk: ">=2.12.0 <3.0.0" 14 | flutter: ">=1.20.0" 15 | 16 | dependencies: 17 | flutter: 18 | sdk: flutter 19 | modal_progress_hud_nsn: ^0.1.0-nullsafety-1 20 | 21 | # The following adds the Cupertino Icons font to your application. 22 | # Use with the CupertinoIcons class for iOS style icons. 23 | cupertino_icons: ^1.0.3 24 | image_picker: ^0.7.5+2 25 | video_thumbnail: ^0.3.3 26 | 27 | dev_dependencies: 28 | flutter_test: 29 | sdk: flutter 30 | 31 | jmessage_flutter: 32 | path: ../ 33 | 34 | # For information on the generic Dart part of this file, see the 35 | # following page: https://www.dartlang.org/tools/pub/pubspec 36 | 37 | # The following section is specific to Flutter. 38 | flutter: 39 | 40 | # The following line ensures that the Material Icons font is 41 | # included with your application, so that you can use the icons in 42 | # the material Icons class. 43 | uses-material-design: true 44 | 45 | # To add assets to your application, add an assets section, like this: 46 | assets: 47 | - assets/nav_close.png 48 | # - images/a_dot_burr.jpeg 49 | # - images/a_dot_ham.jpeg 50 | 51 | # An image asset can refer to one or more resolution-specific "variants", see 52 | # https://flutter.io/assets-and-images/#resolution-aware. 53 | 54 | # For details regarding adding assets from package dependencies, see 55 | # https://flutter.io/assets-and-images/#from-packages 56 | 57 | # To add custom fonts to your application, add a fonts section here, 58 | # in this "flutter" section. Each entry in this list should have a 59 | # "family" key with the font family name, and a "fonts" key with a 60 | # list giving the asset and other descriptors for the font. For 61 | # example: 62 | # fonts: 63 | # - family: Schyler 64 | # fonts: 65 | # - asset: fonts/Schyler-Regular.ttf 66 | # - asset: fonts/Schyler-Italic.ttf 67 | # style: italic 68 | # - family: Trajan Pro 69 | # fonts: 70 | # - asset: fonts/TrajanPro.ttf 71 | # - asset: fonts/TrajanPro_Bold.ttf 72 | # weight: 700 73 | # 74 | # For details regarding fonts from package dependencies, 75 | # see https://flutter.io/custom-fonts/#from-packages 76 | -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vagrant/ 3 | .sconsign.dblite 4 | .svn/ 5 | 6 | .DS_Store 7 | *.swp 8 | profile 9 | 10 | DerivedData/ 11 | build/ 12 | GeneratedPluginRegistrant.h 13 | GeneratedPluginRegistrant.m 14 | 15 | .generated/ 16 | 17 | *.pbxuser 18 | *.mode1v3 19 | *.mode2v3 20 | *.perspectivev3 21 | 22 | !default.pbxuser 23 | !default.mode1v3 24 | !default.mode2v3 25 | !default.perspectivev3 26 | 27 | xcuserdata 28 | 29 | *.moved-aside 30 | 31 | *.pyc 32 | *sync/ 33 | Icon? 34 | .tags* 35 | 36 | /Flutter/Generated.xcconfig 37 | -------------------------------------------------------------------------------- /ios/Assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpush/jmessage-flutter-plugin/f19f8a0f7f1068362a0098314b22a1d6883ff2a5/ios/Assets/.gitkeep -------------------------------------------------------------------------------- /ios/Classes/JMessageHelper.h: -------------------------------------------------------------------------------- 1 | // __ __ ________ 2 | // | | | | \ \ / / | | | | / _______| 3 | // | |____| | \ \/ / | |____| | / / 4 | // | |____| | \ / | |____| | | | _____ 5 | // | | | | / \ | | | | | | |____ | 6 | // | | | | / /\ \ | | | | \ \______| | 7 | // | | | | /_/ \_\ | | | | \_________| 8 | // 9 | // Copyright (c) 2012年 HXHG. All rights reserved. 10 | // http://www.jpush.cn 11 | // Created by liangjianguo 12 | // 13 | 14 | 15 | #import 16 | #import 17 | 18 | //static NSString *JMessageAppKey; 19 | 20 | @interface JMessageHelper : NSObject 21 | @property(nonatomic, strong)NSString *JMessageAppKey; 22 | @property(strong,nonatomic)NSDictionary *launchOptions; 23 | + (JMessageHelper *)shareInstance; 24 | 25 | @end 26 | 27 | 28 | @interface NSArray (JMessage) 29 | - (NSArray *)mapObjectsUsingBlock:(id (^)(id obj, NSUInteger idx))block; 30 | @end 31 | 32 | @interface NSDictionary (JMessage) 33 | -(NSString*)toJsonString; 34 | @end 35 | 36 | @interface NSString (JMessage) 37 | -(NSDictionary*)toDictionary; 38 | @end 39 | 40 | @interface JMSGConversation (JMessage) 41 | -(NSMutableDictionary*)conversationToDictionary; 42 | @end 43 | 44 | @interface JMSGUser (JMessage) 45 | -(NSMutableDictionary*)userToDictionary; 46 | @end 47 | 48 | @interface JMSGGroup (JMessage) 49 | -(NSMutableDictionary*)groupToDictionary; 50 | @end 51 | 52 | @interface JMSGGroupMemberInfo (JMessage) 53 | - (NSMutableDictionary *)memberToDictionary; 54 | @end 55 | 56 | @interface JMSGGroupInfo (JMessage) 57 | -(NSMutableDictionary*)groupToDictionary; 58 | @end 59 | 60 | @interface JMSGMessage (JMessage) 61 | - (NSMutableDictionary *)messageToDictionary; 62 | @end 63 | 64 | @interface JMSGChatRoom (JMessage) 65 | - (NSMutableDictionary *)chatRoomToDictionary; 66 | @end 67 | 68 | @interface JMSGApplyJoinGroupEvent (JMessage) 69 | - (NSMutableDictionary *)eventToDictionary; 70 | @end 71 | 72 | @interface JMSGGroupAdminRejectApplicationEvent (JMessage) 73 | - (NSMutableDictionary *)eventToDictionary; 74 | @end 75 | 76 | @interface JMSGGroupAdminApprovalEvent (JMessage) 77 | - (NSMutableDictionary *)eventToDictionary; 78 | @end 79 | 80 | @interface JMSGGroupNicknameChangeEvent (JMessage) 81 | - (NSMutableDictionary *)eventToDictionary; 82 | @end 83 | 84 | -------------------------------------------------------------------------------- /ios/Classes/JMessageHelper.m: -------------------------------------------------------------------------------- 1 | // __ __ ________ 2 | // | | | | \ \ / / | | | | / _______| 3 | // | |____| | \ \/ / | |____| | / / 4 | // | |____| | \ / | |____| | | | _____ 5 | // | | | | / \ | | | | | | |____ | 6 | // | | | | / /\ \ | | | | \ \______| | 7 | // | | | | /_/ \_\ | | | | \_________| 8 | // 9 | // Copyright (c) 2012年 HXHG. All rights reserved. 10 | // http://www.jpush.cn 11 | // Created by liangjianguo 12 | // 13 | 14 | 15 | #import "JMessageHelper.h" 16 | #ifdef NSFoundationVersionNumber_iOS_9_x_Max 17 | #import 18 | #endif 19 | @interface JMessageHelper () 20 | @end 21 | 22 | @implementation JMessageHelper 23 | 24 | + (JMessageHelper *)shareInstance { 25 | static JMessageHelper *instance = nil; 26 | static dispatch_once_t onceToken; 27 | dispatch_once(&onceToken, ^{ 28 | instance = [[JMessageHelper alloc] init]; 29 | }); 30 | return instance; 31 | } 32 | @end 33 | 34 | 35 | #pragma mark - category 36 | 37 | @implementation NSDictionary (JPush) 38 | -(NSString*)toJsonString{ 39 | NSError *error; 40 | NSData *data = [NSJSONSerialization dataWithJSONObject:self options:0 error:&error]; 41 | NSString *jsonString = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]; 42 | return jsonString; 43 | } 44 | @end 45 | 46 | @implementation NSString (JPush) 47 | -(NSMutableDictionary*)toDictionary{ 48 | NSError *error; 49 | NSData *jsonData = [self dataUsingEncoding:NSUTF8StringEncoding]; 50 | NSMutableDictionary *dict = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&error]; 51 | return dict; 52 | } 53 | @end 54 | 55 | @implementation JMSGConversation (JMessage) 56 | -(NSMutableDictionary*)conversationToDictionary{ 57 | NSMutableDictionary *dict = [NSMutableDictionary dictionary]; 58 | 59 | switch (self.conversationType) { 60 | case kJMSGConversationTypeSingle:{ 61 | JMSGUser *user = self.target; 62 | dict[@"target"] = [user userToDictionary]; 63 | dict[@"conversationType"] = @"single"; 64 | break; 65 | } 66 | 67 | case kJMSGConversationTypeGroup:{ 68 | JMSGGroup *group = self.target; 69 | dict[@"target"] = [group groupToDictionary]; 70 | dict[@"conversationType"] = @"group"; 71 | break; 72 | } 73 | case kJMSGConversationTypeChatRoom:{ 74 | JMSGChatRoom *chatroom = self.target; 75 | dict[@"target"] = [chatroom chatRoomToDictionary]; 76 | dict[@"conversationType"] = @"chatRoom"; 77 | break; 78 | } 79 | } 80 | 81 | if (self.latestMessage) { 82 | dict[@"latestMessage"] = [self.latestMessage messageToDictionary]; 83 | } 84 | 85 | dict[@"unreadCount"] = self.unreadCount ?: @(0); 86 | dict[@"title"] = [self title] ?: @""; 87 | dict[@"extras"] = [self getConversationExtras] ?: @{}; 88 | return dict; 89 | } 90 | 91 | 92 | @end 93 | 94 | @implementation JMSGUser (JMessage) 95 | -(NSMutableDictionary*)userToDictionary{ 96 | NSMutableDictionary *dict = [NSMutableDictionary dictionary]; 97 | dict[@"type"] = @"user"; 98 | dict[@"username"] = self.username ?: @""; 99 | dict[@"nickname"] = self.nickname ?: @""; 100 | dict[@"birthday"] = self.birthday ?: @""; 101 | dict[@"region"] = self.region ?: @""; 102 | dict[@"signature"] = self.signature ?: @""; 103 | dict[@"address"] = [self address] ?: @""; 104 | dict[@"noteName"] = self.noteName ?: @""; 105 | dict[@"noteText"] = self.noteText ?: @""; 106 | dict[@"appKey"] = self.appKey ?: @""; 107 | dict[@"isNoDisturb"] = @(self.isNoDisturb); 108 | dict[@"isInBlackList"] = @(self.isInBlacklist); 109 | dict[@"isFriend"] = @(self.isFriend); 110 | dict[@"extras"] = self.extras ?: @{}; 111 | 112 | if([[NSFileManager defaultManager] fileExistsAtPath: [self thumbAvatarLocalPath] ?: @""]){ 113 | dict[@"avatarThumbPath"] = [self thumbAvatarLocalPath]; 114 | } else { 115 | dict[@"avatarThumbPath"] = @""; 116 | } 117 | 118 | switch (self.gender) { 119 | case kJMSGUserGenderUnknown: 120 | dict[@"gender"] = @"unknown"; 121 | break; 122 | case kJMSGUserGenderFemale: 123 | dict[@"gender"] = @"female"; 124 | break; 125 | case kJMSGUserGenderMale: 126 | dict[@"gender"] = @"male"; 127 | break; 128 | default: 129 | break; 130 | } 131 | return dict; 132 | } 133 | 134 | - (NSString *)getLargeAvatarFilePath { 135 | NSString *avatarPath = [self largeAvatarLocalPath]; 136 | if([[NSFileManager defaultManager] fileExistsAtPath: avatarPath]){ 137 | return avatarPath; 138 | } else { 139 | return @""; 140 | } 141 | } 142 | @end 143 | 144 | @implementation JMSGGroup (JMessage) 145 | -(NSMutableDictionary*)groupToDictionary { 146 | NSMutableDictionary *dict = [NSMutableDictionary dictionary]; 147 | dict[@"type"] = @"group"; 148 | dict[@"id"] = self.gid; 149 | dict[@"name"] = self.name ?: @""; 150 | dict[@"desc"] = self.desc ?: @""; 151 | dict[@"level"] = self.level; 152 | dict[@"flag"] = self.flag; 153 | dict[@"owner"] = self.owner; 154 | dict[@"ownerAppKey"] = self.ownerAppKey; 155 | dict[@"maxMemberCount"] = @([self.maxMemberCount integerValue]); 156 | dict[@"isNoDisturb"] = @(self.isNoDisturb); 157 | dict[@"isBlocked"] = @(self.isShieldMessage); 158 | dict[@"displayName"] = self.displayName; 159 | 160 | switch (self.groupType) { 161 | case kJMSGGroupTypePublic: 162 | dict[@"groupType"] = @"public"; 163 | break; 164 | 165 | default: 166 | dict[@"groupType"] = @"private"; 167 | break; 168 | } 169 | return dict; 170 | } 171 | @end 172 | 173 | 174 | @implementation JMSGGroupMemberInfo (JMessage) 175 | - (NSMutableDictionary *)memberToDictionary { 176 | NSMutableDictionary *dict = [NSMutableDictionary dictionary]; 177 | dict[@"user"] = [self.user userToDictionary]; 178 | dict[@"groupNickname"] = [self displayName] ? : @""; 179 | 180 | switch (self.memberType) { 181 | case kJMSGGroupMemberTypeOrdinary: 182 | dict[@"memberType"] = @"ordinary"; 183 | break; 184 | case kJMSGGroupMemberTypeOwner: 185 | 186 | break; 187 | case kJMSGGroupMemberTypeAdmin: 188 | dict[@"memberType"] = @"admin"; 189 | break; 190 | } 191 | dict[@"joinGroupTime"] = @(self.ctime); 192 | return dict; 193 | } 194 | @end 195 | 196 | @implementation JMSGGroupInfo (JMessage) 197 | -(NSMutableDictionary*)groupToDictionary { 198 | NSMutableDictionary *dict = [NSMutableDictionary dictionary]; 199 | dict[@"id"] = self.gid; 200 | dict[@"name"] = self.name; 201 | dict[@"desc"] = self.desc; 202 | dict[@"maxMemberCount"] = @([self.maxMemberCount integerValue]); 203 | switch (self.groupType) { 204 | case kJMSGGroupTypePublic: 205 | dict[@"groupType"] = @"public"; 206 | break; 207 | 208 | default: 209 | dict[@"groupType"] = @"private"; 210 | break; 211 | } 212 | return dict; 213 | } 214 | @end 215 | 216 | @implementation JMSGMessage (JMessage) 217 | 218 | - (NSMutableDictionary *)messageToDictionary { 219 | NSMutableDictionary *dict = [NSMutableDictionary new]; 220 | 221 | dict[@"id"] = self.msgId; // 本地数据库中的消息 Id。 222 | dict[@"serverMessageId"] = self.serverMessageId; // 服务器端对应的消息 Id。 223 | dict[@"from"] = [self.fromUser userToDictionary]; 224 | 225 | switch (self.status) { 226 | case kJMSGMessageStatusSendDraft: 227 | dict[@"state"] = @"draft"; 228 | break; 229 | case kJMSGMessageStatusSending: 230 | dict[@"state"] = @"sending"; 231 | break; 232 | case kJMSGMessageStatusSendSucceed: 233 | dict[@"state"] = @"send_succeed"; 234 | break; 235 | case kJMSGMessageStatusReceiving: 236 | dict[@"state"] = @"receiving"; 237 | break; 238 | case kJMSGMessageStatusSendFailed: 239 | dict[@"state"] = @"send_failed"; 240 | break; 241 | case kJMSGMessageStatusReceiveDownloadFailed: 242 | dict[@"state"] = @"download_failed"; 243 | break; 244 | case kJMSGMessageStatusSendUploadSucceed: 245 | dict[@"state"] = @"upload_succeed"; 246 | break; 247 | case kJMSGMessageStatusReceiveSucceed: 248 | dict[@"state"] = @"received"; 249 | break; 250 | case kJMSGMessageStatusSendUploadFailed: 251 | dict[@"state"] = @"upload_failed"; 252 | break; 253 | default: 254 | dict[@"state"] = @"send_succeed"; 255 | break; 256 | } 257 | 258 | if (self.content.extras != nil) { 259 | dict[@"extras"] = self.content.extras; 260 | } 261 | 262 | dict[@"isSend"] = [NSNumber numberWithBool: !self.isReceived]; 263 | switch (self.targetType) { 264 | case kJMSGConversationTypeSingle:{ 265 | JMSGUser *user = self.target; 266 | dict[@"target"] = [user userToDictionary]; 267 | break; 268 | } 269 | case kJMSGConversationTypeGroup:{ 270 | JMSGGroup *group = self.target; 271 | dict[@"target"] = [group groupToDictionary]; 272 | break; 273 | } 274 | case kJMSGConversationTypeChatRoom:{ 275 | JMSGChatRoom *chatroom = self.target; 276 | dict[@"target"] = [chatroom chatRoomToDictionary]; 277 | break; 278 | } 279 | } 280 | 281 | dict[@"createTime"] = self.timestamp; 282 | 283 | switch (self.contentType) { 284 | case kJMSGContentTypeUnknown: { 285 | dict[@"type"] = @"unknown"; 286 | break; 287 | } 288 | case kJMSGContentTypeText: { 289 | dict[@"type"] = @"text"; 290 | JMSGTextContent *textContent = (JMSGTextContent *) self.content; 291 | dict[@"text"] = textContent.text; 292 | break; 293 | } 294 | case kJMSGContentTypeImage: { 295 | dict[@"type"] = @"image"; 296 | JMSGImageContent *imageContent = (JMSGImageContent *) self.content; 297 | dict[@"thumbPath"] = [imageContent thumbImageLocalPath]; 298 | break; 299 | } 300 | case kJMSGContentTypeVoice: { 301 | dict[@"type"] = @"voice"; 302 | dict[@"path"] = [self getOriginMediaFilePath]; 303 | JMSGVoiceContent *voiceContent = (JMSGVoiceContent *) self.content; 304 | dict[@"duration"] = [voiceContent duration]; 305 | break; 306 | } 307 | case kJMSGContentTypeCustom: { 308 | dict[@"type"] = @"custom"; 309 | JMSGCustomContent *customContent = (JMSGCustomContent *) self.content; 310 | dict[@"customObject"] = customContent.customDictionary; 311 | break; 312 | } 313 | case kJMSGContentTypeEventNotification: { 314 | dict[@"type"] = @"event"; 315 | JMSGEventContent *eventContent = (JMSGEventContent *) self.content; 316 | 317 | NSArray *userArr = [eventContent getEventToUsernameList]; 318 | dict[@"usernames"] = userArr; 319 | dict[@"nicknames"] = userArr; 320 | 321 | switch (eventContent.eventType) { 322 | case kJMSGEventNotificationAcceptedFriendInvitation: { 323 | dict[@"eventType"] = @"acceptedFriendInvitation"; 324 | break; 325 | } 326 | case kJMSGEventNotificationAddGroupMembers: { 327 | dict[@"eventType"] = @"group_member_added"; 328 | break; 329 | } 330 | case kJMSGEventNotificationCreateGroup: { 331 | dict[@"eventType"] = @"createGroup"; 332 | break; 333 | } 334 | case kJMSGEventNotificationCurrentUserInfoChange: { 335 | dict[@"eventType"] = @"currentUserInfoChange"; 336 | break; 337 | } 338 | case kJMSGEventNotificationDeclinedFriendInvitation: { 339 | dict[@"eventType"] = @"declinedFriendInvitation"; 340 | break; 341 | } 342 | case kJMSGEventNotificationDeletedFriend: { 343 | dict[@"eventType"] = @"deletedFriend"; 344 | break; 345 | } 346 | case kJMSGEventNotificationExitGroup: { 347 | dict[@"eventType"] = @"group_member_exit"; 348 | break; 349 | } 350 | case kJMSGEventNotificationLoginKicked: { 351 | dict[@"eventType"] = @"loginKicked"; 352 | break; 353 | } 354 | case kJMSGEventNotificationMessageRetract: { 355 | dict[@"eventType"] = @"messageRetract"; 356 | break; 357 | } 358 | case kJMSGEventNotificationReceiveFriendInvitation: { 359 | dict[@"eventType"] = @"receiveFriendInvitation"; 360 | break; 361 | } 362 | case kJMSGEventNotificationReceiveServerFriendUpdate: { 363 | dict[@"eventType"] = @"receiveServerFriendUpdate"; 364 | break; 365 | } 366 | case kJMSGEventNotificationRemoveGroupMembers: { 367 | dict[@"eventType"] = @"group_member_removed"; 368 | break; 369 | } 370 | case kJMSGEventNotificationServerAlterPassword: { 371 | dict[@"eventType"] = @"serverAlterPassword"; 372 | break; 373 | } 374 | case kJMSGEventNotificationUpdateGroupInfo: { 375 | dict[@"eventType"] = @"group_info_updated"; 376 | break; 377 | } 378 | case kJMSGEventNotificationUserLoginStatusUnexpected: { 379 | dict[@"eventType"] = @"userLoginStatusUnexpected"; 380 | break; 381 | } 382 | case kJMSGEventNotificationGroupTypeChange: { 383 | dict[@"eventType"] = @"group_type_changed"; 384 | break; 385 | } 386 | case kJMSGEventNotificationDissolveGroup: { 387 | dict[@"eventType"] = @"group_dissolved"; 388 | break; 389 | } 390 | default: 391 | break; 392 | } 393 | break; 394 | } 395 | case kJMSGContentTypeFile: { 396 | dict[@"type"] = @"file"; 397 | JMSGFileContent *fileContent = (JMSGFileContent *) self.content; 398 | dict[@"fileName"] = [fileContent fileName]; 399 | break; 400 | } 401 | case kJMSGContentTypeLocation: { 402 | dict[@"type"] = @"location"; 403 | JMSGLocationContent *locationContent = (JMSGLocationContent *) self.content; 404 | dict[@"latitude"] = @([locationContent.latitude doubleValue]); 405 | dict[@"longitude"] = @([locationContent.longitude doubleValue]); 406 | dict[@"scale"] = @([locationContent.scale intValue]); 407 | dict[@"address"] = locationContent.address; 408 | break; 409 | } 410 | case kJMSGContentTypePrompt: { 411 | dict[@"type"] = @"prompt"; 412 | JMSGPromptContent *promptContent = (JMSGPromptContent *) self.content; 413 | dict[@"promptText"] = promptContent.promptText; 414 | break; 415 | } 416 | default: 417 | break; 418 | } 419 | return dict; 420 | } 421 | 422 | - (NSString *)getOriginMediaFilePath { 423 | JMSGMediaAbstractContent *content = (JMSGMediaAbstractContent *) self.content; 424 | NSString *mediaPath = [content originMediaLocalPath]; 425 | if([[NSFileManager defaultManager] fileExistsAtPath:mediaPath]){ 426 | return mediaPath; 427 | } else { 428 | return @""; 429 | } 430 | } 431 | 432 | - (NSString *)getFullPathWith:(NSString *) path { 433 | NSString * homeDir = NSHomeDirectory(); 434 | return [NSString stringWithFormat:@"%@/Documents/%@", homeDir,path]; 435 | } 436 | @end 437 | 438 | @implementation JMSGChatRoom (JMessage) 439 | - (NSMutableDictionary *)chatRoomToDictionary { 440 | NSMutableDictionary *dict = @{}.mutableCopy; 441 | dict[@"type"] = @"chatRoom"; 442 | dict[@"roomId"] = self.roomID; 443 | dict[@"name"] = self.name; 444 | dict[@"appKey"] = self.appkey; 445 | dict[@"description"] = self.description; 446 | dict[@"createTime"] = self.ctime; 447 | dict[@"maxMemberCount"] = @([self.maxMemberCount integerValue]); 448 | dict[@"memberCount"] = @(self.totalMemberCount); 449 | 450 | return dict; 451 | } 452 | @end 453 | 454 | 455 | 456 | @implementation NSArray (JMessage) 457 | 458 | - (NSArray *)mapObjectsUsingBlock:(id (^)(id obj, NSUInteger idx))block { 459 | NSMutableArray *result = [NSMutableArray arrayWithCapacity:[self count]]; 460 | [self enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { 461 | [result addObject:block(obj, idx)]; 462 | }]; 463 | return result; 464 | } 465 | 466 | @end 467 | 468 | @implementation JMSGApplyJoinGroupEvent (JMessage) 469 | - (NSMutableDictionary *)eventToDictionary { 470 | NSMutableDictionary *dict = @{}.mutableCopy; 471 | 472 | dict[@"eventId"] = self.eventID; 473 | dict[@"groupId"] = self.groupID; 474 | dict[@"isInitiativeApply"] = @(self.isInitiativeApply); 475 | dict[@"sendApplyUser"] = self.sendApplyUser != nil ? @{} : [self.sendApplyUser userToDictionary]; 476 | if (self.joinGroupUsers != nil) { 477 | NSArray *userDicArr = [self.joinGroupUsers mapObjectsUsingBlock:^id(id obj, NSUInteger idx) { 478 | JMSGUser *user = obj; 479 | return [user userToDictionary]; 480 | }]; 481 | dict[@"joinGroupUsers"] = userDicArr; 482 | } 483 | dict[@"reason"] = self.reason; 484 | return dict; 485 | } 486 | @end 487 | 488 | 489 | @implementation JMSGGroupAdminRejectApplicationEvent (JMessage) 490 | - (NSMutableDictionary *)eventToDictionary { 491 | NSMutableDictionary *dict = @{}.mutableCopy; 492 | dict[@"groupId"] = self.groupID; 493 | dict[@"reason"] = self.rejectReason; 494 | dict[@"groupManager"] = [self.groupManager userToDictionary]; 495 | return dict; 496 | } 497 | @end 498 | 499 | @implementation JMSGGroupAdminApprovalEvent (JMessage) 500 | - (NSMutableDictionary *)eventToDictionary { 501 | NSMutableDictionary *dict = @{}.mutableCopy; 502 | dict[@"isAgree"] = @(self.isAgreeApply); 503 | dict[@"applyEventId"] = self.applyEventID; 504 | dict[@"groupId"] = self.groupID; 505 | dict[@"groupAdmin"] = [self.groupAdmin userToDictionary]; 506 | 507 | if (self.users != nil) { 508 | NSArray *userDicArr = [self.users mapObjectsUsingBlock:^id(id obj, NSUInteger idx) { 509 | JMSGUser *user = obj; 510 | return [user userToDictionary]; 511 | }]; 512 | dict[@"users"] = userDicArr; 513 | } 514 | return dict; 515 | } 516 | @end 517 | 518 | @implementation JMSGGroupNicknameChangeEvent (JMessage) 519 | - (NSMutableDictionary *)eventToDictionary { 520 | NSMutableDictionary *dict = @{}.mutableCopy; 521 | dict[@"group"] = [self.group groupToDictionary]; 522 | dict[@"fromMemberInfo"] = [self.fromMemberInfo memberToDictionary]; 523 | dict[@"toMemberInfo"] = [self.toMemberInfo memberToDictionary]; 524 | dict[@"ctime"] = @(self.ctime); 525 | return dict; 526 | } 527 | @end 528 | -------------------------------------------------------------------------------- /ios/Classes/JmessageFlutterPlugin.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface JmessageFlutterPlugin : NSObject 5 | @property NSString *JMessageAppKey; 6 | @property NSDictionary *launchOptions; 7 | @property FlutterMethodChannel *channel; 8 | @end 9 | -------------------------------------------------------------------------------- /ios/jmessage_flutter.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html 3 | # 4 | Pod::Spec.new do |s| 5 | s.name = 'jmessage_flutter' 6 | s.version = '0.0.1' 7 | s.summary = 'A new flutter plugin project.' 8 | s.description = <<-DESC 9 | A new flutter plugin project. 10 | DESC 11 | s.homepage = 'http://example.com' 12 | s.license = { :file => '../LICENSE' } 13 | s.author = { 'Your Company' => 'email@example.com' } 14 | s.source = { :path => '.' } 15 | s.source_files = 'Classes/**/*' 16 | s.public_header_files = 'Classes/**/*.h' 17 | s.dependency 'Flutter' 18 | s.dependency 'JMessage' 19 | s.ios.deployment_target = '8.0' 20 | s.static_framework = true 21 | end 22 | 23 | -------------------------------------------------------------------------------- /jmessage_flutter.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /jmessage_flutter_android.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: jmessage_flutter 2 | description: JIGUANG officially supported JMessage Flutter plugin (Android & iOS). 极光推送官方支持的 Flutter 插件(Android & iOS)(https://www.jiguang.cn). 3 | version: 2.2.1 4 | homepage: https://www.jiguang.cn 5 | 6 | environment: 7 | sdk: ">=2.12.0 <3.0.0" 8 | flutter: ">=1.20.0" 9 | 10 | dependencies: 11 | platform: ^3.0.0 12 | flutter: 13 | sdk: flutter 14 | 15 | # For information on the generic Dart part of this file, see the 16 | # following page: https://www.dartlang.org/tools/pub/pubspec 17 | 18 | # The following section is specific to Flutter. 19 | flutter: 20 | plugin: 21 | platforms: 22 | android: 23 | package: com.jiguang.jmessageflutter 24 | pluginClass: JmessageFlutterPlugin 25 | ios: 26 | pluginClass: JmessageFlutterPlugin 27 | 28 | # To add assets to your plugin package, add an assets section, like this: 29 | # assets: 30 | # - images/a_dot_burr.jpeg 31 | # - images/a_dot_ham.jpeg 32 | # 33 | # For details regarding assets in packages, see 34 | # https://flutter.io/assets-and-images/#from-packages 35 | # 36 | # An image asset can refer to one or more resolution-specific "variants", see 37 | # https://flutter.io/assets-and-images/#resolution-aware. 38 | 39 | # To add custom fonts to your plugin package, add a fonts section here, 40 | # in this "flutter" section. Each entry in this list should have a 41 | # "family" key with the font family name, and a "fonts" key with a 42 | # list giving the asset and other descriptors for the font. For 43 | # example: 44 | # fonts: 45 | # - family: Schyler 46 | # fonts: 47 | # - asset: fonts/Schyler-Regular.ttf 48 | # - asset: fonts/Schyler-Italic.ttf 49 | # style: italic 50 | # - family: Trajan Pro 51 | # fonts: 52 | # - asset: fonts/TrajanPro.ttf 53 | # - asset: fonts/TrajanPro_Bold.ttf 54 | # weight: 700 55 | # 56 | # For details regarding fonts in packages, see 57 | # https://flutter.io/custom-fonts/#from-packages 58 | --------------------------------------------------------------------------------