diff --git a/android/.project b/android/.project new file mode 100644 index 0000000..b6ece59 --- /dev/null +++ b/android/.project @@ -0,0 +1,17 @@ + + + android__ + Project android__ created by Buildship. + + + + + org.eclipse.buildship.core.gradleprojectbuilder + + + + + + org.eclipse.buildship.core.gradleprojectnature + + diff --git a/android/.settings/org.eclipse.buildship.core.prefs b/android/.settings/org.eclipse.buildship.core.prefs new file mode 100644 index 0000000..c329865 --- /dev/null +++ b/android/.settings/org.eclipse.buildship.core.prefs @@ -0,0 +1,13 @@ +arguments= +auto.sync=false +build.scans.enabled=false +connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER) +connection.project.dir= +eclipse.preferences.version=1 +gradle.user.home= +java.home=/Library/Java/JavaVirtualMachines/temurin-11.jdk/Contents/Home +jvm.arguments= +offline.mode=false +override.workspace.settings=true +show.console.view=true +show.executions.view=true diff --git a/android/src/main/java/com/jiguang/jmessageflutter/JmessageFlutterPlugin.java b/android/src/main/java/com/jiguang/jmessageflutter/JmessageFlutterPlugin.java index 6d2cf85..c421bf5 100644 --- a/android/src/main/java/com/jiguang/jmessageflutter/JmessageFlutterPlugin.java +++ b/android/src/main/java/com/jiguang/jmessageflutter/JmessageFlutterPlugin.java @@ -22,6 +22,10 @@ import java.util.List; import java.util.Map; +import cn.jmessage.support.google.gson.Gson; +import cn.jmessage.support.google.gson.GsonBuilder; +import cn.jmessage.support.google.gson.JsonObject; +import cn.jmessage.support.google.gson.JsonParser; import cn.jpush.im.android.api.ContactManager; import cn.jpush.im.android.api.JMessageClient; import cn.jpush.im.android.api.callback.CreateGroupCallback; @@ -190,6 +194,8 @@ public void onMethodCall(MethodCall call, Result result) { getMessageById(call, result); } else if (call.method.equals("deleteMessageById")) { deleteMessageById(call, result); + } else if (call.method.equals("deleteAllMessage")) { + deleteAllMessage(call, result); } else if (call.method.equals("sendInvitationRequest")) { sendInvitationRequest(call, result); } else if (call.method.equals("acceptInvitation")) { @@ -252,6 +258,8 @@ public void onMethodCall(MethodCall call, Result result) { downloadVoiceFile(call, result); } else if (call.method.equals("downloadFile")) { downloadFile(call, result); + } else if (call.method.equals("downloadVideoFile")) { + downloadVideoFile(call, result); } else if (call.method.equals("createConversation")) { createConversation(call, result); } else if (call.method.equals("deleteConversation")) { @@ -312,8 +320,8 @@ public void onMethodCall(MethodCall call, Result result) { setMessageHaveRead(call, result); } else if (call.method.equals("sendVideoMessage")) { sendVideoMessage(call, result); - } else if(call.method.equals("getMessageHaveReadStatus")){ - getMessageHaveReadStatus(call,result); + } else if (call.method.equals("getMessageHaveReadStatus")) { + getMessageHaveReadStatus(call, result); } else { result.notImplemented(); } @@ -691,9 +699,10 @@ public void gotResult(int status, String desc, Bitmap bitmap) { private void setConversationExtras(MethodCall call, Result result) { HashMap map = call.arguments(); Conversation conversation; - JSONObject extra = null; + String extra = null; try { + Gson gson = new Gson(); JSONObject params = new JSONObject(map); conversation = JMessageUtils.getConversation(params); @@ -703,7 +712,7 @@ private void setConversationExtras(MethodCall call, Result result) { } if (params.has("extras")) { - extra = params.getJSONObject("extras"); + extra = gson.toJson(map.get("extras")); } } catch (JSONException e) { e.printStackTrace(); @@ -711,7 +720,8 @@ private void setConversationExtras(MethodCall call, Result result) { return; } - String extraStr = extra == null ? "" : extra.toString(); + String extraStr = extra == null ? "" : extra; + Log.d(TAG, "setConversationExtras: " + extraStr); conversation.updateConversationExtra(extraStr); handleResult(toJson(conversation), 0, null, result); } @@ -771,6 +781,34 @@ private void createMessage(MethodCall call, Result result) { String address = params.getString("address"); content = new LocationContent(latitude, longitude, scale, address); break; + case "video": + String thumbImagePath = "", thumbFormat = "", videoPath, videoFileName = ""; + videoPath = params.getString("videoPath"); + if (params.has("thumbFormat")) { + thumbFormat = params.getString("thumbFormat"); + } + if (params.has("thumbImagePath")) { + thumbImagePath = params.getString("thumbImagePath"); + } + if (params.has("duration")) { + duration = params.getInt("duration"); + } else { + mediaPlayer = MediaPlayer.create(mContext, Uri.parse(videoPath)); + duration = mediaPlayer.getDuration() / 1000; + mediaPlayer.release(); + } + if (params.has("videoFileName")) { + videoFileName = params.getString("videoFileName"); + } + + File videoFile = getFile(videoPath); + + Bitmap bitmap = null; + if (!TextUtils.isEmpty(thumbImagePath)) { + bitmap = BitmapFactory.decodeFile(thumbImagePath); + } + content = new VideoContent(bitmap, thumbFormat, videoFile, videoFileName, duration); + break; default: content = new CustomContent(); break; @@ -1511,6 +1549,33 @@ private void deleteMessageById(MethodCall call, Result result) { } } + private void deleteAllMessage(MethodCall call, Result result) { + HashMap map = call.arguments(); + Conversation conversation; + try { + JSONObject params = new JSONObject(map); + conversation = JMessageUtils.getConversation(params); + if (conversation == null) { + handleResult(ERR_CODE_CONVERSATION, "Can't get conversation", result); + return; + } + } catch (JSONException e) { + e.printStackTrace(); + handleResult(ERR_CODE_PARAMETER, ERR_MSG_PARAMETER, result); + return; + } + boolean success = conversation.deleteAllMessage(); + + if (success) { + result.success(null); + } else { + HashMap error = new HashMap(); + error.put("code", ERR_CODE_MESSAGE); + error.put("description", "no success"); + result.error(ERR_CODE_MESSAGE + "", ERR_MSG_MESSAGE, ""); + } + } + private void sendInvitationRequest(MethodCall call, final Result result) { HashMap map = call.arguments(); String username, appKey, reason; @@ -2288,13 +2353,11 @@ private void downloadThumbImage(MethodCall call, final Result result) { return; } - if (msg.getContentType() != ContentType.image) { - handleResult(ERR_CODE_MESSAGE, "Message type isn't image", result); + if (msg.getContentType() != ContentType.image && msg.getContentType() != ContentType.video) { + handleResult(ERR_CODE_MESSAGE, "Message type isn't image/video", result); return; } - - ImageContent content = (ImageContent) msg.getContent(); - content.downloadThumbnailImage(msg, new DownloadCompletionCallback() { + DownloadCompletionCallback cb = new DownloadCompletionCallback() { @Override public void onComplete(int status, String desc, File file) { if (status == 0) { @@ -2302,12 +2365,20 @@ public void onComplete(int status, String desc, File file) { res.put("messageId", msg.getId()); res.put("filePath", file.getAbsolutePath()); handleResult(res, status, desc, result); - } else { handleResult(status, desc, result); } } - }); + }; + if (msg.getContentType() == ContentType.image) { + ImageContent content = (ImageContent) msg.getContent(); + content.downloadThumbnailImage(msg, cb); + } else { + VideoContent content = (VideoContent) msg.getContent(); + content.downloadThumbImage(msg, cb); + } + + } private void downloadOriginalImage(MethodCall call, final Result result) { @@ -2390,7 +2461,6 @@ public void onComplete(int status, String desc, File file) { private void downloadFile(MethodCall call, final Result result) { HashMap map = call.arguments(); final Message msg; - try { JSONObject params = new JSONObject(map); msg = JMessageUtils.getMessage(params); @@ -2426,6 +2496,44 @@ public void onComplete(int status, String desc, File file) { }); } + private void downloadVideoFile(MethodCall call, final Result result) { + HashMap map = call.arguments(); + final Message msg; + try { + JSONObject params = new JSONObject(map); + msg = JMessageUtils.getMessage(params); + if (msg == null) { + handleResult(ERR_CODE_MESSAGE, ERR_MSG_MESSAGE, result); + return; + } + } catch (JSONException e) { + e.printStackTrace(); + handleResult(ERR_CODE_PARAMETER, ERR_MSG_PARAMETER, result); + return; + } + + if (msg.getContentType() != ContentType.video) { + handleResult(ERR_CODE_MESSAGE, "Message type isn't video", result); + return; + } + + VideoContent content = (VideoContent) msg.getContent(); + content.downloadVideoFile(msg, new DownloadCompletionCallback() { + @Override + public void onComplete(int status, String desc, File file) { + if (status == 0) { + HashMap res = new HashMap(); + res.put("messageId", msg.getId()); + res.put("filePath", file.getAbsolutePath()); + handleResult(res, status, desc, result); + + } else { + handleResult(status, desc, result); + } + } + }); + } + private void createConversation(MethodCall call, Result result) { HashMap map = call.arguments(); try { diff --git a/android/src/main/java/com/jiguang/jmessageflutter/JsonUtils.java b/android/src/main/java/com/jiguang/jmessageflutter/JsonUtils.java index 87b4f91..b556fee 100644 --- a/android/src/main/java/com/jiguang/jmessageflutter/JsonUtils.java +++ b/android/src/main/java/com/jiguang/jmessageflutter/JsonUtils.java @@ -16,6 +16,7 @@ import java.util.List; import java.util.Map; +import cn.jmessage.support.google.gson.Gson; import cn.jmessage.support.google.gson.JsonElement; import cn.jmessage.support.google.gson.JsonObject; import cn.jmessage.support.google.gson.JsonParser; @@ -437,13 +438,16 @@ static HashMap toJson(Conversation conversation) { } if (!TextUtils.isEmpty(conversation.getExtra())) { - HashMap extrasMap = new HashMap(); +// HashMap extrasMap = new HashMap(); String extras = conversation.getExtra(); - JsonParser parser = new JsonParser(); - JsonObject jsonObject = parser.parse(extras).getAsJsonObject(); - for (Map.Entry entry : jsonObject.entrySet()) { - extrasMap.put(entry.getKey(), entry.getValue().toString()); - } +// JsonParser parser = new JsonParser(); +// JsonObject jsonObject = parser.parse(extras).getAsJsonObject(); + // gson to map + Gson gson = new Gson(); + HashMap extrasMap = gson.fromJson(extras, HashMap.class); +// for (Map.Entry entry : jsonObject.entrySet()) { +// extrasMap.put(entry.getKey(), entry.getValue()); +// } json.put("extras", extrasMap); } else { json.put("extras", new HashMap()); diff --git a/example/.flutter-plugins-dependencies b/example/.flutter-plugins-dependencies index bc25b71..1511d79 100644 --- a/example/.flutter-plugins-dependencies +++ b/example/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"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"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"image_picker","path":"/Users/Shared/flutter/.pub-cache/hosted/pub.flutter-io.cn/image_picker-0.7.5+4/","dependencies":[]},{"name":"jmessage_flutter","path":"/Users/jethro/Documents/vip/zhs-app/plugins/jmessage-flutter-plugin/","dependencies":[]},{"name":"modal_progress_hud_nsn","path":"/Users/Shared/flutter/.pub-cache/hosted/pub.flutter-io.cn/modal_progress_hud_nsn-0.1.0-nullsafety-1/","dependencies":[]},{"name":"video_thumbnail","path":"/Users/Shared/flutter/.pub-cache/hosted/pub.flutter-io.cn/video_thumbnail-0.3.3/","dependencies":[]}],"android":[{"name":"flutter_plugin_android_lifecycle","path":"/Users/Shared/flutter/.pub-cache/hosted/pub.flutter-io.cn/flutter_plugin_android_lifecycle-2.0.5/","dependencies":[]},{"name":"image_picker","path":"/Users/Shared/flutter/.pub-cache/hosted/pub.flutter-io.cn/image_picker-0.7.5+4/","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"jmessage_flutter","path":"/Users/jethro/Documents/vip/zhs-app/plugins/jmessage-flutter-plugin/","dependencies":[]},{"name":"modal_progress_hud_nsn","path":"/Users/Shared/flutter/.pub-cache/hosted/pub.flutter-io.cn/modal_progress_hud_nsn-0.1.0-nullsafety-1/","dependencies":[]},{"name":"video_thumbnail","path":"/Users/Shared/flutter/.pub-cache/hosted/pub.flutter-io.cn/video_thumbnail-0.3.3/","dependencies":[]}],"macos":[],"linux":[],"windows":[],"web":[{"name":"image_picker_for_web","path":"/Users/Shared/flutter/.pub-cache/hosted/pub.flutter-io.cn/image_picker_for_web-2.1.4/","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-12-01 16:32:45.794089","version":"2.5.3"} \ No newline at end of file diff --git a/example/android/.project b/example/android/.project new file mode 100644 index 0000000..0e0a1ba --- /dev/null +++ b/example/android/.project @@ -0,0 +1,17 @@ + + + android_ + Project android_ created by Buildship. + + + + + org.eclipse.buildship.core.gradleprojectbuilder + + + + + + org.eclipse.buildship.core.gradleprojectnature + + diff --git a/example/android/.settings/org.eclipse.buildship.core.prefs b/example/android/.settings/org.eclipse.buildship.core.prefs new file mode 100644 index 0000000..2fded2c --- /dev/null +++ b/example/android/.settings/org.eclipse.buildship.core.prefs @@ -0,0 +1,13 @@ +arguments= +auto.sync=false +build.scans.enabled=false +connection.gradle.distribution=GRADLE_DISTRIBUTION(VERSION(7.0-rc-1)) +connection.project.dir= +eclipse.preferences.version=1 +gradle.user.home= +java.home=/Library/Java/JavaVirtualMachines/temurin-11.jdk/Contents/Home +jvm.arguments= +offline.mode=false +override.workspace.settings=true +show.console.view=true +show.executions.view=true diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index ce62977..37a1302 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -48,7 +48,7 @@ android { manifestPlaceholders = [ JPUSH_PKGNAME : applicationId, - JPUSH_APPKEY : "你自己应用的 AppKey", //极光 上注册的包名对应的 Appkey. + JPUSH_APPKEY : "6f571d35cfcedc7f3150ce0b", //极光 上注册的包名对应的 Appkey. JPUSH_CHANNEL : "developer-default", //暂时填写默认值即可. ] } diff --git a/example/ios/Flutter/AppFrameworkInfo.plist b/example/ios/Flutter/AppFrameworkInfo.plist index 9367d48..8d4492f 100644 --- a/example/ios/Flutter/AppFrameworkInfo.plist +++ b/example/ios/Flutter/AppFrameworkInfo.plist @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 8.0 + 9.0 diff --git a/example/ios/Flutter/Flutter.podspec b/example/ios/Flutter/Flutter.podspec index 5ca3041..663d5b2 100644 --- a/example/ios/Flutter/Flutter.podspec +++ b/example/ios/Flutter/Flutter.podspec @@ -1,18 +1,18 @@ # # NOTE: This podspec is NOT to be published. It is only used as a local source! +# This is a generated file; do not edit or check into version control. # Pod::Spec.new do |s| s.name = 'Flutter' s.version = '1.0.0' s.summary = 'High-performance, high-fidelity mobile apps.' - s.description = <<-DESC -Flutter provides an easy and productive way to build and deploy high-performance mobile apps for Android and iOS. - DESC s.homepage = 'https://flutter.io' s.license = { :type => 'MIT' } s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' } s.source = { :git => 'https://github.com/flutter/engine', :tag => s.version.to_s } - s.ios.deployment_target = '8.0' - s.vendored_frameworks = 'Flutter.framework' + s.ios.deployment_target = '9.0' + # Framework linking is handled by Flutter tooling, not CocoaPods. + # Add a placeholder to satisfy `s.dependency 'Flutter'` plugin podspecs. + s.vendored_frameworks = 'path/to/nothing' end diff --git a/example/ios/Flutter/flutter_export_environment.sh b/example/ios/Flutter/flutter_export_environment.sh index 159b7cb..512bfea 100755 --- a/example/ios/Flutter/flutter_export_environment.sh +++ b/example/ios/Flutter/flutter_export_environment.sh @@ -1,11 +1,10 @@ #!/bin/sh # This is a generated file; do not edit or check into version control. -export "FLUTTER_ROOT=D:\Workspace\android\flutter" -export "FLUTTER_APPLICATION_PATH=D:\Workspace\flutter\jmessage-flutter-plugin\example" +export "FLUTTER_ROOT=/Users/Shared/flutter" +export "FLUTTER_APPLICATION_PATH=/Users/jethro/Documents/vip/zhs-app/plugins/jmessage-flutter-plugin/example" export "COCOAPODS_PARALLEL_CODE_SIGN=true" -export "FLUTTER_TARGET=lib\main.dart" +export "FLUTTER_TARGET=lib/main.dart" export "FLUTTER_BUILD_DIR=build" -export "SYMROOT=${SOURCE_ROOT}/../build\ios" export "FLUTTER_BUILD_NAME=1.0.0" export "FLUTTER_BUILD_NUMBER=1" export "DART_OBFUSCATION=false" diff --git a/example/ios/Podfile b/example/ios/Podfile index 7c6cb6f..d5eed7b 100644 --- a/example/ios/Podfile +++ b/example/ios/Podfile @@ -4,60 +4,38 @@ # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' -def parse_KV_file(file, separator='=') - file_abs_path = File.expand_path(file) - if !File.exists? file_abs_path - return []; +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches end - pods_ary = [] - skip_line_start_symbols = ["#", "/"] - File.foreach(file_abs_path) { |line| - next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } - plugin = line.split(pattern=separator) - if plugin.length == 2 - podname = plugin[0].strip() - path = plugin[1].strip() - podpath = File.expand_path("#{path}", file_abs_path) - pods_ary.push({:name => podname, :path => podpath}); - else - puts "Invalid plugin specification: #{line}" - end - } - return pods_ary + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" end +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + target 'Runner' do - # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock - # referring to absolute paths on developers' machines. - system('rm -rf .symlinks') - system('mkdir -p .symlinks/plugins') - - # Flutter Pods - generated_xcode_build_settings = parse_KV_file('./Flutter/Generated.xcconfig') - if generated_xcode_build_settings.empty? - puts "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter packages get is executed first." - end - generated_xcode_build_settings.map { |p| - if p[:name] == 'FLUTTER_FRAMEWORK_DIR' - symlink = File.join('.symlinks', 'flutter') - File.symlink(File.dirname(p[:path]), symlink) - pod 'Flutter', :path => File.join(symlink, File.basename(p[:path])) - end - } - - # Plugin Pods - plugin_pods = parse_KV_file('../.flutter-plugins') - plugin_pods.map { |p| - symlink = File.join('.symlinks', 'plugins', p[:name]) - File.symlink(p[:path], symlink) - pod p[:name], :path => File.join(symlink, 'ios') - } + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) end post_install do |installer| installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) target.build_configurations.each do |config| - config.build_settings['ENABLE_BITCODE'] = 'NO' + config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '9.0' end end end diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index 93ee562..e43d6a7 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -150,7 +150,6 @@ 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - 03468A242FE0B80CF0AD9B45 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -220,24 +219,6 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 03468A242FE0B80CF0AD9B45 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", - "${PODS_ROOT}/../.symlinks/flutter/ios/Flutter.framework", - ); - name = "[CP] Embed Pods Frameworks"; - outputPaths = ( - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -364,7 +345,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -411,7 +392,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; @@ -430,6 +411,7 @@ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 8X2A38Q9VD; ENABLE_BITCODE = NO; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "i386 arm64"; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Flutter", diff --git a/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata index 1d526a1..919434a 100644 --- a/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ b/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -2,6 +2,6 @@ + location = "self:"> diff --git a/ios/Classes/JMessageHelper.m b/ios/Classes/JMessageHelper.m index 39df780..e26d947 100644 --- a/ios/Classes/JMessageHelper.m +++ b/ios/Classes/JMessageHelper.m @@ -182,7 +182,7 @@ - (NSMutableDictionary *)memberToDictionary { dict[@"memberType"] = @"ordinary"; break; case kJMSGGroupMemberTypeOwner: - + dict[@"memberType"] = @"owner"; break; case kJMSGGroupMemberTypeAdmin: dict[@"memberType"] = @"admin"; @@ -297,6 +297,15 @@ - (NSMutableDictionary *)messageToDictionary { dict[@"thumbPath"] = [imageContent thumbImageLocalPath]; break; } + case kJMSGContentTypeVideo: { + dict[@"type"] = @"video"; + JMSGVideoContent *videoContent = (JMSGVideoContent *) self.content; + dict[@"videoPath"] = [videoContent originMediaLocalPath]; + dict[@"thumbImagePath"] = [videoContent videoThumbImageLocalPath]; + dict[@"duration"] = [videoContent duration]; + dict[@"videoFileName"] = [videoContent fileName]; + break; + } case kJMSGContentTypeVoice: { dict[@"type"] = @"voice"; dict[@"path"] = [self getOriginMediaFilePath]; diff --git a/ios/Classes/JmessageFlutterPlugin.m b/ios/Classes/JmessageFlutterPlugin.m index c3a2159..5349896 100644 --- a/ios/Classes/JmessageFlutterPlugin.m +++ b/ios/Classes/JmessageFlutterPlugin.m @@ -410,6 +410,8 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { [self getMessageByServerMessageId:call result:result]; } else if([@"deleteMessageById" isEqualToString:call.method]) { [self deleteMessageById:call result:result]; + } else if([@"deleteAllMessage" isEqualToString:call.method]) { + [self deleteAllMessage:call result:result]; } else if([@"sendInvitationRequest" isEqualToString:call.method]) { [self sendInvitationRequest:call result:result]; } else if([@"acceptInvitation" isEqualToString:call.method]) { @@ -470,6 +472,8 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { [self downloadOriginalImage:call result:result]; } else if([@"downloadVoiceFile" isEqualToString:call.method]) { [self downloadVoiceFile:call result:result]; + } else if([@"downloadVideoFile" isEqualToString:call.method]) { + [self downloadVideoFile:call result:result]; } else if([@"downloadFile" isEqualToString:call.method]) { [self downloadFile:call result:result]; } else if([@"createConversation" isEqualToString:call.method]) { @@ -1323,6 +1327,25 @@ - (void)deleteMessageById:(FlutterMethodCall*)call result:(FlutterResult)result }]; } +- (void)deleteAllMessage:(FlutterMethodCall*)call result:(FlutterResult)result { + NSDictionary *param = call.arguments; + [self getConversationWithDictionary:param callback:^(JMSGConversation *conversation, NSError *error) { + if (error) { + result([error flutterError]); + return; + } + + BOOL res = [conversation deleteAllMessages]; + + if (res) { + result(nil); + } else { + NSError *error = [NSError errorWithDomain:@"delete all message fail!" code: 1 userInfo: nil]; + result([error flutterError]); + } + }]; +} + - (void)sendInvitationRequest:(FlutterMethodCall*)call result:(FlutterResult)result { NSDictionary *param = call.arguments; NSString *appKey = nil; @@ -1981,22 +2004,37 @@ - (void)downloadThumbImage:(FlutterMethodCall*)call result:(FlutterResult)result return; } - if (message.contentType != kJMSGContentTypeImage) { - NSError *error = [NSError errorWithDomain:@"It is not image message!" code: 1 userInfo: nil]; + if (message.contentType != kJMSGContentTypeImage && message.contentType != kJMSGContentTypeVideo) { + NSError *error = [NSError errorWithDomain:@"It is not image/video message!" code: 1 userInfo: nil]; result([error flutterError]); return; } - - JMSGImageContent *content = (JMSGImageContent *) message.content; - - [content thumbImageData:^(NSData *data, NSString *objectId, NSError *error) { - if (error) { - result([error flutterError]); - return; - } - result(@{@"messageId": message.msgId, - @"filePath": content.thumbImageLocalPath ? : @""}); - }]; + if (message.contentType == kJMSGContentTypeImage) { + // 图片消息处理 + JMSGImageContent *content = (JMSGImageContent *) message.content; + + [content thumbImageData:^(NSData *data, NSString *objectId, NSError *error) { + if (error) { + result([error flutterError]); + return; + } + result(@{@"messageId": message.msgId, + @"filePath": content.thumbImageLocalPath ? : @""}); + }]; + } else if (message.contentType == kJMSGContentTypeVideo) { + // 视频消息处理 + JMSGVideoContent *content = (JMSGVideoContent *) message.content; + + [content videoThumbImageData:^(NSData *data, NSString *objectId, NSError *error) { + if (error) { + result([error flutterError]); + return; + } + result(@{@"messageId": message.msgId, + @"filePath": content.videoThumbImageLocalPath ? : @""}); + }]; + } + }]; } @@ -2122,6 +2160,44 @@ - (void)downloadFile:(FlutterMethodCall*)call result:(FlutterResult)result { }]; } +// 下载视频文件 +- (void)downloadVideoFile:(FlutterMethodCall*)call result:(FlutterResult)result { + NSDictionary *param = call.arguments; + [self getConversationWithDictionary:param callback:^(JMSGConversation *conversation, NSError *error) { + + JMSGMessage *message = nil; + NSString *msgid = param[@"messageId"]; + if ([msgid hasPrefix:@"msgId"]) { + message = [conversation messageWithMessageId:msgid]; + }else{ + message = [conversation messageWithServerMessageId:msgid]; + } + if (!message) { + NSError *error = [NSError errorWithDomain:@"cann't find this message!" code: 1 userInfo: nil]; + result([error flutterError]); + return; + } + + if (message.contentType != kJMSGContentTypeVideo) { + NSError *error = [NSError errorWithDomain:@"It is not video message!" code: 1 userInfo: nil]; + result([error flutterError]); + return; + } + + JMSGVideoContent *content = (JMSGVideoContent *) message.content; + [content videoDataWithProgress:nil completionHandler:^(NSData *data, NSString *objectId, NSError *error) { + if (error) { + result([error flutterError]); + return; + } + JMSGVideoContent *videoContent = (JMSGVideoContent *) message.content; + result(@{@"messageId": message.msgId, + @"filePath":[videoContent originMediaLocalPath] ? : @""}); + }]; + + }]; +} + - (void)createConversation:(FlutterMethodCall*)call result:(FlutterResult)result { NSDictionary *param = call.arguments; diff --git a/lib/jmessage_flutter.dart b/lib/jmessage_flutter.dart index 6fe1c24..661b1a0 100644 --- a/lib/jmessage_flutter.dart +++ b/lib/jmessage_flutter.dart @@ -566,6 +566,11 @@ class JmessageFlutter { Map? customObject, double? latitude, double? longitude, + String? videoPath, + String? thumbImagePath, + String? thumbFormat, + String? videoFileName, + int? duration, int? scale, String? address, Map? extras, @@ -587,6 +592,11 @@ class JmessageFlutter { 'longitude': longitude, 'scale': scale, 'address': address, + 'videoPath': videoPath, + 'thumbImagePath': thumbImagePath, + 'thumbFormat': thumbFormat, + 'videoFileName': videoFileName, + 'duration': duration, }); Map resMap = await _channel.invokeMethod( @@ -611,7 +621,9 @@ class JmessageFlutter { }; } - param..addAll(optionMap)..addAll({'id': message?.id}); + param + ..addAll(optionMap) + ..addAll({'id': message?.id}); Map resMap = await _channel.invokeMethod( 'sendDraftMessage', param..removeWhere((key, value) => value == null)); var res = JMNormalMessage.generateMessageFromJson(resMap); @@ -639,7 +651,9 @@ class JmessageFlutter { param..addAll({'extras': extras}); } - param..addAll(optionMap)..addAll({'text': text}); + param + ..addAll(optionMap) + ..addAll({'text': text}); Map resMap = await _channel.invokeMethod( 'sendTextMessage', param..removeWhere((key, value) => value == null)); @@ -669,7 +683,9 @@ class JmessageFlutter { param..addAll({'extras': extras}); } - param..addAll(optionMap)..addAll({'path': path}); + param + ..addAll(optionMap) + ..addAll({'path': path}); Map resMap = await _channel.invokeMethod( 'sendImageMessage', param..removeWhere((key, value) => value == null)); @@ -699,7 +715,9 @@ class JmessageFlutter { param..addAll({'extras': extras}); } - param..addAll(optionMap)..addAll({'path': path}); + param + ..addAll(optionMap) + ..addAll({'path': path}); Map resMap = await _channel.invokeMethod( 'sendVoiceMessage', param..removeWhere((key, value) => value == null)); @@ -729,7 +747,9 @@ class JmessageFlutter { param..addAll({'extras': extras}); } - param..addAll(optionMap)..addAll({'customObject': customObject}); + param + ..addAll(optionMap) + ..addAll({'customObject': customObject}); Map resMap = await _channel.invokeMethod( 'sendCustomMessage', param..removeWhere((key, value) => value == null)); @@ -798,7 +818,9 @@ class JmessageFlutter { param..addAll({'extras': extras}); } - param..addAll(optionMap)..addAll({'path': path}); + param + ..addAll(optionMap) + ..addAll({'path': path}); Map resMap = await _channel.invokeMethod( 'sendFileMessage', param..removeWhere((key, value) => value == null)); @@ -966,6 +988,19 @@ class JmessageFlutter { return; } + /// 删除全部消息 + /// target 聊天对象, JMSingle | JMGroup + Future deleteAllMessage({ + required dynamic type, + + /// (JMSingle | JMGroup | JMChatRoom) + }) async { + Map param = type.toJson(); + await _channel.invokeMethod( + 'deleteAllMessage', param..removeWhere((key, value) => value == null)); + return; + } + Future sendInvitationRequest({ required String? username, required String? reason, @@ -1338,6 +1373,21 @@ class JmessageFlutter { return {'messageId': resJson['messageId'], 'filePath': resJson['filePath']}; } + /// 下载视频 + /// target 聊天对象, JMSingle | JMGroup | JMChatRoom + /// messageId 本地数据库中的消息 id + Future downloadVideoFile({ + required dynamic target, + required String? messageId, + }) async { + Map param = target.toJson(); + param['messageId'] = messageId; + Map resJson = await _channel.invokeMethod( + 'downloadVideoFile', param..removeWhere((key, value) => value == null)); + + return {'messageId': resJson['messageId'], 'filePath': resJson['filePath']}; + } + Future createConversation({ required dynamic target, //(JMSingle | JMGroup | JMChatRoom) }) async { @@ -2055,7 +2105,7 @@ class JMNormalMessage { case JMMessageType.prompt: return JMPromptMessage.fromJson(json); case JMMessageType.video: - return JMPromptMessage.fromJson(json); + return JMVideoMessage.fromJson(json); } } } @@ -2159,9 +2209,9 @@ class JMLocationMessage extends JMNormalMessage { class JMVideoMessage extends JMNormalMessage { String videoPath; // 视频地址 - String thumbFormat; //视频缩略图格式名 + String? thumbFormat; //视频缩略图格式名 int duration; // 视频时长 - String thumbImagePath; // 视频缩略图 + String? thumbImagePath; // 视频缩略图 String videoFileName; // 视频名称 Map toJson() { @@ -2212,7 +2262,19 @@ class JMPromptMessage extends JMNormalMessage { super.fromJson(json); } -enum JMEventType { group_member_added, group_member_removed, group_member_exit } +enum JMEventType { + group_member_added, + group_member_removed, + group_member_exit, + group_info_updated, + group_member_keep_silence, + group_member_keep_silence_cancel, + group_keeper_added, + group_keeper_removed, + group_dissolved, + group_owner_changed, + group_type_changed, +} class JMEventMessage extends JMNormalMessage { JMEventType eventType; // 事件类型