diff --git a/README.md b/README.md index f560bff..bbd15eb 100644 --- a/README.md +++ b/README.md @@ -12,10 +12,11 @@ - 对接APP用户信息(昵称/头像) - 获取当前客服在线状态 - 获取历史会话 -- 消息提示设置 +- 消息提示音/振动设置 - 消息送达/已读 - 消息撤回 - 输入状态(对方正在输入) +- 发送/播放视频 diff --git a/bytedesk_demo/README.md b/bytedesk_demo/README.md index 48a9b2d..5c7e603 100644 --- a/bytedesk_demo/README.md +++ b/bytedesk_demo/README.md @@ -12,10 +12,11 @@ - 对接APP用户信息(昵称/头像) - 获取当前客服在线状态 - 获取历史会话 -- 消息提示设置 +- 消息提示音/振动设置 - 消息送达/已读 - 消息撤回 - 输入状态(对方正在输入) +- 发送/播放视频 @@ -29,7 +30,7 @@ - [注册账号](https://www.bytedesk.com/antv/user/login) - 获取appkey,登录后台->客服管理->渠道管理->添加应用->appkey - 获取subDomain,也即企业号:登录后台->客服管理->客服账号->企业号 -- 获取技能组workGroupWid +- 获取技能组workGroupWid, 登录后台->技能组->wid ### 第二步:匿名登录 diff --git a/bytedesk_demo/android/app/build.gradle b/bytedesk_demo/android/app/build.gradle index e79fff5..27ee615 100644 --- a/bytedesk_demo/android/app/build.gradle +++ b/bytedesk_demo/android/app/build.gradle @@ -25,7 +25,7 @@ apply plugin: 'com.android.application' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" android { - compileSdkVersion 28 + compileSdkVersion 29 lintOptions { disable 'InvalidPackage' diff --git a/bytedesk_demo/android/build.gradle b/bytedesk_demo/android/build.gradle index e0d7ae2..1209e4c 100644 --- a/bytedesk_demo/android/build.gradle +++ b/bytedesk_demo/android/build.gradle @@ -1,21 +1,27 @@ buildscript { repositories { + maven { url 'http://maven.aliyun.com/nexus/content/groups/public/' } +// maven { url 'https://maven.aliyun.com/repository/jcenter' } google() jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.5.0' + classpath 'com.android.tools.build:gradle:4.1.0' } } allprojects { repositories { +// mavenCentral() + maven { url 'http://maven.aliyun.com/nexus/content/groups/public/' } +// maven { url 'https://maven.aliyun.com/repository/jcenter' } google() jcenter() } } + rootProject.buildDir = '../build' subprojects { project.buildDir = "${rootProject.buildDir}/${project.name}" diff --git a/bytedesk_demo/android/gradle/wrapper/gradle-wrapper.properties b/bytedesk_demo/android/gradle/wrapper/gradle-wrapper.properties index 296b146..e5e73da 100644 --- a/bytedesk_demo/android/gradle/wrapper/gradle-wrapper.properties +++ b/bytedesk_demo/android/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-all.zip diff --git a/bytedesk_demo/android/settings_aar.gradle b/bytedesk_demo/android/settings_aar.gradle new file mode 100644 index 0000000..e7b4def --- /dev/null +++ b/bytedesk_demo/android/settings_aar.gradle @@ -0,0 +1 @@ +include ':app' diff --git a/bytedesk_demo/assets/audio/bytedesk_alarm.wav b/bytedesk_demo/assets/audio/bytedesk_alarm.wav new file mode 100644 index 0000000..61894f4 Binary files /dev/null and b/bytedesk_demo/assets/audio/bytedesk_alarm.wav differ diff --git a/bytedesk_demo/assets/audio/bytedesk_dingdong.wav b/bytedesk_demo/assets/audio/bytedesk_dingdong.wav new file mode 100644 index 0000000..4ca952e Binary files /dev/null and b/bytedesk_demo/assets/audio/bytedesk_dingdong.wav differ diff --git a/bytedesk_demo/assets/audio/bytedesk_newmsg.wav b/bytedesk_demo/assets/audio/bytedesk_newmsg.wav new file mode 100644 index 0000000..1657d35 Binary files /dev/null and b/bytedesk_demo/assets/audio/bytedesk_newmsg.wav differ diff --git a/bytedesk_demo/assets/audio/bytedesk_waiting.wav b/bytedesk_demo/assets/audio/bytedesk_waiting.wav new file mode 100644 index 0000000..3e24674 Binary files /dev/null and b/bytedesk_demo/assets/audio/bytedesk_waiting.wav differ diff --git a/bytedesk_demo/assets/images/feedback/mine_feedback_add_image.png b/bytedesk_demo/assets/images/feedback/mine_feedback_add_image.png new file mode 100755 index 0000000..3e7c5d2 Binary files /dev/null and b/bytedesk_demo/assets/images/feedback/mine_feedback_add_image.png differ diff --git a/bytedesk_demo/assets/images/feedback/mine_feedback_ic_del.png b/bytedesk_demo/assets/images/feedback/mine_feedback_ic_del.png new file mode 100755 index 0000000..3d5e595 Binary files /dev/null and b/bytedesk_demo/assets/images/feedback/mine_feedback_ic_del.png differ diff --git a/bytedesk_demo/ios/Podfile b/bytedesk_demo/ios/Podfile index f7d6a5e..7529df8 100644 --- a/bytedesk_demo/ios/Podfile +++ b/bytedesk_demo/ios/Podfile @@ -1,5 +1,7 @@ # Uncomment this line to define a global platform for your project -# platform :ios, '9.0' +platform :ios, '10.0' +# added by jackning, 20200929 +use_frameworks! # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' diff --git a/bytedesk_demo/lib/main.dart b/bytedesk_demo/lib/main.dart index e3e51c1..e62c5c3 100644 --- a/bytedesk_demo/lib/main.dart +++ b/bytedesk_demo/lib/main.dart @@ -1,29 +1,25 @@ import 'package:bytedesk_kefu/bytedesk_kefu.dart'; import 'package:bytedesk_kefu/util/bytedesk_constants.dart'; import 'package:bytedesk_kefu/util/bytedesk_events.dart'; +import 'package:bytedesk_kefu/util/bytedesk_utils.dart'; +import 'package:bytedesk_demo/notification/custom_notification.dart'; import 'package:bytedesk_demo/page/chat_type_page.dart'; import 'package:bytedesk_demo/page/history_thread_page.dart'; import 'package:bytedesk_demo/page/online_status_page.dart'; -// import 'package:bytedesk_demo/page/setting_page.dart'; +import 'package:bytedesk_demo/page/setting_page.dart'; import 'package:bytedesk_demo/page/user_info_page.dart'; -import 'package:bytedesk_kefu/util/bytedesk_utils.dart'; import 'package:overlay_support/overlay_support.dart'; import 'package:flutter/material.dart'; - -import 'notification/custom_notification.dart'; +import 'package:vibration/vibration.dart'; +import 'package:audioplayers/audio_cache.dart'; void main() { // runApp(MyApp()); - // runApp(MaterialApp( - // debugShowCheckedModeBanner: false, // 去除右上角debug的标签 - // home: MyApp(), - // )); runApp(OverlaySupport( - child: MaterialApp( - debugShowCheckedModeBanner: false, // 去除右上角debug的标签 - home: MyApp(), - ) - )); + child: MaterialApp( + debugShowCheckedModeBanner: false, // 去除右上角debug的标签 + home: MyApp(), + ))); // 参考文档:https://github.com/Bytedesk/bytedesk-flutter // 管理后台:https://www.bytedesk.com/antv/user/login @@ -45,8 +41,7 @@ class MyApp extends StatefulWidget { class _MyAppState extends State with WidgetsBindingObserver { // String _title = '萝卜丝客服Demo'; - // 第二步:到 客服管理->技能组-有一列 ‘唯一ID(wId)’, 默认设置工作组wid - // String _workGroupWid = "201807171659201"; + AudioCache audioCache = AudioCache(); // @override void initState() { @@ -81,6 +76,7 @@ class _MyAppState extends State with WidgetsBindingObserver { title: Text('用户信息'), // 自定义用户资料,设置 trailing: Icon(Icons.keyboard_arrow_right), onTap: () { + // 需要首先调用anonymousLogin之后,再调用设置用户信息接口 Navigator.of(context) .push(new MaterialPageRoute(builder: (context) { return new UserInfoPage(); @@ -123,16 +119,16 @@ class _MyAppState extends State with WidgetsBindingObserver { // // TODO: 意见反馈 // }, // ), - // ListTile( - // title: Text('消息设置'), - // trailing: Icon(Icons.keyboard_arrow_right), - // onTap: () { - // Navigator.of(context) - // .push(new MaterialPageRoute(builder: (context) { - // return new SettingPage(); - // })); - // }, - // ) + ListTile( + title: Text('消息设置'), + trailing: Icon(Icons.keyboard_arrow_right), + onTap: () { + Navigator.of(context) + .push(new MaterialPageRoute(builder: (context) { + return new SettingPage(); + })); + }, + ) ], ).toList()), ); @@ -157,9 +153,30 @@ class _MyAppState extends State with WidgetsBindingObserver { }); } }); - // 监听消息 + // 监听消息,开发者可在此决定是否振动或播放提示音声音 bytedeskEventBus.on().listen((event) { // print('receive message:' + event.message.content); + // 1. 首先将example/assets/audio文件夹中文件拷贝到自己项目;2.在自己项目pubspec.yaml中添加assets + // 播放发送消息提示音 + if (BytedeskKefu.getPlayAudioOnSendMessage() && event.message.isSend == 1) { + print('play send audio'); + // 修改为自己项目中语音文件路径 + audioCache.play('audio/bytedesk_dingdong.wav'); + } + if (event.message.isSend == 1) { + // 自己发送的消息,直接返回 + return; + } + // 接收消息播放提示音 + if (BytedeskKefu.getPlayAudioOnReceiveMessage() && event.message.isSend == 0) { + print('play receive audio'); + audioCache.play('audio/bytedesk_dingdong.wav'); + } + // 振动 + if (BytedeskKefu.getVibrateOnReceiveMessage() && event.message.isSend == 0) { + print('should vibrate'); + vibrate(); + } if (event.message.type == BytedeskConstants.MESSAGE_TYPE_TEXT) { print('文字消息: ' + event.message.content); // 判断当前是否客服页面,如否,则显示顶部通知栏 @@ -176,9 +193,10 @@ class _MyAppState extends State with WidgetsBindingObserver { ); }, duration: Duration(milliseconds: 4000)); } - } else if (event.message.type == BytedeskConstants.MESSAGE_TYPE_IMAGE) { print('图片消息:' + event.message.imageUrl); + } else if (event.message.type == BytedeskConstants.MESSAGE_TYPE_VIDEO) { + print('视频消息:' + event.message.imageUrl); } else { print('其他类型消息'); } @@ -202,10 +220,15 @@ class _MyAppState extends State with WidgetsBindingObserver { // } // } + void vibrate() async { + if (await Vibration.hasVibrator()) { + Vibration.vibrate(); + } + } + @override void dispose() { WidgetsBinding.instance.removeObserver(this); super.dispose(); } - } diff --git a/bytedesk_demo/lib/page/chat_type_page.dart b/bytedesk_demo/lib/page/chat_type_page.dart index 4df1643..05e09de 100644 --- a/bytedesk_demo/lib/page/chat_type_page.dart +++ b/bytedesk_demo/lib/page/chat_type_page.dart @@ -13,8 +13,10 @@ class ChatTypePage extends StatefulWidget { } class _ChatTypePageState extends State { + // 第二步:到 客服管理->技能组-有一列 ‘唯一ID(wId)’, 默认设置工作组wid // 说明:一个技能组可以分配多个客服,访客会按照一定的规则分配给组内的各个客服账号 - String _workGroupWid = "201807171659201"; + String _workGroupWid = "201807171659201"; // 默认人工 + String _workGroupWidRobot = "201809061716221"; // 默认机器人 // 说明:直接发送给此一个客服账号,一对一会话 String _agentUid = "201808221551193"; // @@ -33,7 +35,14 @@ class _ChatTypePageState extends State { title: Text('技能组客服'), trailing: Icon(Icons.keyboard_arrow_right), onTap: () { - BytedeskKefu.startWorkGroupChat(context, _workGroupWid, "技能组客服"); + BytedeskKefu.startWorkGroupChat(context, _workGroupWid, "技能组客服-默认人工"); + }, + ), + ListTile( + title: Text('技能组客服-机器人'), + trailing: Icon(Icons.keyboard_arrow_right), + onTap: () { + BytedeskKefu.startWorkGroupChat(context, _workGroupWidRobot, "技能组客服-默认机器人"); }, ), ListTile( @@ -52,14 +61,14 @@ class _ChatTypePageState extends State { "categoryCode": "100010003", "client": "flutter" }); - BytedeskKefu.startWorkGroupChatShop(context, _workGroupWid, "技能组客服", custom); + BytedeskKefu.startWorkGroupChatShop(context, _workGroupWid, "技能组客服-电商", custom); }, ), ListTile( title: Text('技能组客服-附言'), trailing: Icon(Icons.keyboard_arrow_right), onTap: () { - BytedeskKefu.startWorkGroupChatPostscript(context, _workGroupWid, "技能组客服", "随便说点什么吧,我会自动发送给客服"); + BytedeskKefu.startWorkGroupChatPostscript(context, _workGroupWid, "技能组客服-附言", "随便说点什么吧,我会自动发送给客服"); }, ), Container( diff --git a/bytedesk_demo/lib/page/setting_page.dart b/bytedesk_demo/lib/page/setting_page.dart index 7d00c32..6eac97c 100644 --- a/bytedesk_demo/lib/page/setting_page.dart +++ b/bytedesk_demo/lib/page/setting_page.dart @@ -11,14 +11,14 @@ class SettingPage extends StatefulWidget { } class _SettingPageState extends State { - // bool _playAudioOnSendMessage = false; - // bool _playAudioOnReceiveMessage = false; + bool _playAudioOnSendMessage = false; + bool _playAudioOnReceiveMessage = false; bool _vibrateOnReceiveMessage = false; // @override void initState() { - // _playAudioOnSendMessage = BytedeskKefu.getPlayAudioOnSendMessage(); - // _playAudioOnReceiveMessage = BytedeskKefu.getPlayAudioOnReceiveMessage(); + _playAudioOnSendMessage = BytedeskKefu.getPlayAudioOnSendMessage(); + _playAudioOnReceiveMessage = BytedeskKefu.getPlayAudioOnReceiveMessage(); _vibrateOnReceiveMessage = BytedeskKefu.getVibrateOnReceiveMessage(); super.initState(); } @@ -34,26 +34,26 @@ class _SettingPageState extends State { children: ListTile.divideTiles( context: context, tiles: [ - // ListTileSwitch( - // value: _playAudioOnSendMessage, - // onChanged: (value) { - // setState(() { - // _playAudioOnSendMessage = value; - // }); - // BytedeskKefu.setPlayAudioOnSendMessage(value); - // }, - // title: Text('TODO: 发送消息时播放声音'), - // ), - // ListTileSwitch( - // value: _playAudioOnReceiveMessage, - // onChanged: (value) { - // setState(() { - // _playAudioOnReceiveMessage = value; - // }); - // BytedeskKefu.setPlayAudioOnReceiveMessage(value); - // }, - // title: Text('TODO: 收到消息时播放声音'), - // ), + ListTileSwitch( + value: _playAudioOnSendMessage, + onChanged: (value) { + setState(() { + _playAudioOnSendMessage = value; + }); + BytedeskKefu.setPlayAudioOnSendMessage(value); + }, + title: Text('发送消息时播放声音'), + ), + ListTileSwitch( + value: _playAudioOnReceiveMessage, + onChanged: (value) { + setState(() { + _playAudioOnReceiveMessage = value; + }); + BytedeskKefu.setPlayAudioOnReceiveMessage(value); + }, + title: Text('收到消息时播放声音'), + ), ListTileSwitch( value: _vibrateOnReceiveMessage, onChanged: (value) { diff --git a/bytedesk_demo/lib/page/user_info_page.dart b/bytedesk_demo/lib/page/user_info_page.dart index b289d1c..d808349 100644 --- a/bytedesk_demo/lib/page/user_info_page.dart +++ b/bytedesk_demo/lib/page/user_info_page.dart @@ -1,7 +1,9 @@ import 'package:bytedesk_kefu/bytedesk_kefu.dart'; +import 'package:bytedesk_kefu/util/bytedesk_constants.dart'; import 'package:flutter/material.dart'; import 'package:fluttertoast/fluttertoast.dart'; +// 需要首先调用anonymousLogin之后,再调用此接口 // 自定义用户信息接口-对接APP用户信息 class UserInfoPage extends StatefulWidget { UserInfoPage({Key key}) : super(key: key); @@ -12,8 +14,7 @@ class UserInfoPage extends StatefulWidget { class _UserInfoPageState extends State { String _nickname = ''; - String _avatar = - 'https://chainsnow.oss-cn-shenzhen.aliyuncs.com/avatars/chrome_default_avatar.png'; + String _avatar = BytedeskConstants.DEFAULT_AVATA; @override void initState() { _getProfile(); @@ -41,7 +42,7 @@ class _UserInfoPageState extends State { ), ListTile( leading: Image.network( - _avatar ?? 'https://chainsnow.oss-cn-shenzhen.aliyuncs.com/avatars/chrome_default_avatar.png', + _avatar ?? BytedeskConstants.DEFAULT_AVATA, height: 30, width: 30, ), diff --git a/bytedesk_demo/pubspec.yaml b/bytedesk_demo/pubspec.yaml index f09fc22..94189cd 100644 --- a/bytedesk_demo/pubspec.yaml +++ b/bytedesk_demo/pubspec.yaml @@ -33,13 +33,19 @@ dependencies: list_tile_switch: ^0.0.2 # 应用内-顶部通知栏 https://pub.dev/packages/overlay_support/ overlay_support: ^1.0.5 + # 播放提示音 https://pub.dev/packages/audioplayers + audioplayers: ^0.17.0 + # 振动 https://pub.dev/packages/vibration + # 针对报错fatal error: 'vibration/vibration-Swift.h' file not found #import , ld: library not found for -lvibration + # 请在ios/Podfile中添加:use_frameworks! + vibration: ^1.7.2 # https://pub.dev/packages/bytedesk_kefu - bytedesk_kefu: ^0.2.6 + bytedesk_kefu: ^0.3.0 # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^0.1.3 + cupertino_icons: ^1.0.0 dev_dependencies: flutter_test: @@ -60,6 +66,9 @@ flutter: # assets: # - images/a_dot_burr.jpeg # - images/a_dot_ham.jpeg + assets: + - assets/audio/ + - assets/images/feedback/ # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/assets-and-images/#resolution-aware.