海豚APP新增生成聊天二维码和对话链接的功能,注册即可马上分享。复制链接或者将保存的二维码图片发给客户即可聊天。客户可通过该二维码或者链接与客服聊天,客服通过海豚客服【在线工作台】进行即可应答。
登录网址海豚客服系统后台,选择【设置】-【系统接入】-【新增渠道】
设置【渠道名称--使用场景--确定--复制链接/二维码】。即可将生成二维码图片或者链接发给客户。客户可通过该二维码或者链接与客服聊天,客服通过海豚客服【在线工作台】进行应答即可。
微信公众平台包括微信公众号、微信小程序。两种方接入入微信公众号系统
1.打开海豚客服系统后台,选择【系统接入】-【微信公众号】-【新增渠道】
设置【新增渠道】-- 【渠道名称(必填项)】--【确定】
弹出公众平台账号授权二维码,使用公众平台绑定的运营权限为管理员的个人微信号扫描授权。
管理员进行授权操作之后,页面自动跳转至新增渠道页面。点击【部署配置】,该公众平台(小程序)即接入成功。多个微信公众平台可多次点击“新增渠道”。重复上个步骤。使用时,点击所需接入的微信公众号,点击“部署配置”,微信公众号管理员进行授权操作即可进入。
微信公众平台包括微信公众号、微信小程序。两种方接入入微信公众号系统
1.打开海豚客服系统后台,选择【系统接入】-【微信小程序】-【新增渠道】
设置【新增渠道】-- 【渠道名称(必填项)】--【确定】
弹出公众平台账号授权二维码,使用公众平台绑定的运营权限为管理员的个人微信号扫描授权。
管理员进行授权操作之后,页面自动跳转至新增渠道页面。点击【部署配置】,该公众平台(公众号)即接入成功。多个微信公众平台可多次点击“新增渠道”。重复上个步骤。使用时,点击所需接入的微信公众号,点击“部署配置”,微信公众号管理员进行授权操作即可进入。
选择【系统接入】-【网站】-【新增渠道】
设置【新增渠道--渠道名称--确定】,部署配置,复制链接,并由前端开发人员进行网站配置。
可以选择【下载源码】自行配置,访问源码index.html需带上参数
参数为下图_ht()括号中链接,取index.html后面#开始到最后(包含#号)
具体粘贴方法如下:
选择【系统接入】-【APP】-【新增渠道】
设置【新增渠道--渠道名称--确定】,部署配置,复制链接,并由APP开发工作人员在APP上进行配置。
1.首先下载dolphin-release.aar文件到工程主module(通常为app)的libs目录下,如下图所示:
2.在工程主module的build.gradle文件中的android{}花括号中添加代码如下:
repositories {
flatDir{
dirs 'libs'
}
}
具体位置参照下图所示:
3.在工程主module的build.gradle文件中的dependencies{}花括号中添加以下代码:
implementation(name: 'dolphin-release', ext: 'aar')
具体位置参照下图所示:
4.主要!即将打开的会话页面Activity(开发者自己定义,除会话窗口以外的UI都需要自己定义,增强可塑性)需要继承DolphinActivity(此activity在刚刚导入的arr包中,是抽象AppCompatActivity类),开发者自己定义的此activity页面需要布局一个WebView控件,用来展示H5会话窗口,另外,开放了几个对外方法,您只需要重写这些方法,就能做到相关功能,具体如下:
import com.club17j.dolphin.DolphinActivity;
public class SessionActivity extends DolphinActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_session);
WebView webView = findViewById(R.id.webView);
//这个方法的调用是重点,主要功能逻辑都在里面,是父类的方法,只需要 传入要展示的webView
setWebViewSetting(webView);
}
@Override
protected void loadUrl(WebView webView) {
//此父类方法是加载指定H5页面链接的逻辑,如果需要加载自己的url,请注释掉,然后调用 webView.loadUrl("开发者指定的url");
super.loadUrl(webView);
//webView.loadUrl("开发者指定的url");
}
@Override
public void onReceivedTitle(WebView view, String title) {
//接收webView加载的H5页面的标题,用于刷新开发者自己的标题UI
}
@Override
public void onProgressChanged(WebView webView, int i) {
//接收webView加载的H5页面的进度,用于刷新开发者自己的UI
}
}
5.安卓补充一
关于从加载某链接的WebView所在的Activity或者Fragment返回前一页(自己app的原生页面)的方法(看自己APP情况选择操作):
可以在WebView所在视图布局自行添加顶部标题返回按钮(如果不需要,则可以忽略;如果需要则请观看下一补充),该返回按钮点击和安卓手机底部物理返回键点击事件处理逻辑相同(都需要添加后面所说的逻辑代码)
如果所在视图是在Activity上,那么返回前一页面的代码逻辑很简单,finish()就行
@Override
public void onClick(View view) {
if(view.getId==返回按钮的id){
finish();
}
}
如果需要重写其物理返回键监听方法,如下:
如果用的是me.yokeyword.fragmentation.SupportActivity,则是
@Override
public void onBackPressedSupport() {
finish();
}
如果用的是普通的Activity,则是
@Override
public boolean onBackPressed() {
finish();
return true;
}
如果所在视图是在Fragment上,如下:
如果用的是me.yokeyword.fragmentation.SupportFragment则pop()就行
@Override
public void onClick(View view) {
switch (view.getId()) {
case 返回按钮的id:
pop();
break;
}
}
如果需要重写其物理返回键监听方法,如下:
@Override
public boolean onBackPressedSupport() {
pop();
return true;//必须是返回true才是重写成功
}
如果用的是普通的Fragment,则是
怎么显示出来的就对应的怎么消失或者移去
@Override
public void onClick(View view) {
switch (view.getId()) {
case 返回按钮的id:
//出现_mActivity.getSupportFragmentManager().beginTransaction().add(即将被替换的View的id,fragment).commit();
//出现_mActivity.getSupportFragmentManager().beginTransaction().show(fragment).commit();
_mActivity.getSupportFragmentManager().beginTransaction().hide(fragment).commit();
_mActivity.getSupportFragmentManager().beginTransaction().remove(fragment).commit();
break;
}
}
处理物理返回键:
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
//必须在onCreateView方法之后调用
requireActivity().getOnBackPressedDispatcher().addCallback(getViewLifecycleOwner(), new OnBackPressedCallback(true) {
@Override
public void handleOnBackPressed() {
//该事件是否自行处理 true:该事件不向上传递(即上层activity和fragment不响应返回键事件) , false:该fragment不再响应事件
//todo 此处添加回退前一页逻辑代码
setEnabled(false);
}
});
}
6.安卓补充二
关于如何添加顶部标题和返回按钮:
以下代码为加载链接的Activity的布局文件代码,其中id为header_back_button的ImageButton(也可以换成“返回”文字的TextView,代码中注释掉的即是,把注释放开,然后再把控件ImageButton注释掉就行)是返回按钮,
id为的header_title_text_view的TextView是显示标题的控件,
id为的webView的WebView是要加载链接的控件,
arrow_left2为自己定义返回按钮的箭头图片名arrow_left2.png
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:id="@+id/header_view"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#ffffff"
android:orientation="horizontal">
<ImageButton
android:id="@+id/header_back_button"
android:layout_width="50dp"
android:layout_height="match_parent"
android:background="@null"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:scaleType="center"
app:srcCompat="@drawable/arrow_left2"
tools:ignore="ContentDescription" />
<!--<TextView-->
<!--android:id="@+id/header_back_button"-->
<!--android:layout_width="@dimen/_50dip"-->
<!--android:layout_height="match_parent"-->
<!--android:gravity="center"-->
<!--android:text="返回" />-->
<TextView
android:id="@+id/header_title_text_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginEnd="50dp"
android:ellipsize="end"
android:gravity="center"
android:includeFontPadding="false"
android:lines="1"
android:textColor="#030303"
android:textSize="16sp" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:background="#dcdcdc" />
<WebView
android:id="@+id/webView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff" />
</LinearLayout>
该Activity中控制顶部标题、返回按钮、WebView加载链接以及返回主app页面的相关逻辑全部代码如下:
public class SesssionActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sesssion);
//设置顶部标题,具体标题自行修改
((TextView) findViewById(R.id.header_title_text_view)).setText("在线客服");
//返回按钮监听以及返回逻辑
findViewById(R.id.header_title_text_view).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!isFinishing()) {
finish();
}
}
});
WebView webView = findViewById(R.id.webView);
initWebViewSettings(webView);
webView.loadUrl(需要加载的聊天对话框链接);
}
private void initWebViewSettings(WebView webView) {
if (webView == null) {
return;
}
WebSettings ws = webView.getSettings();
// 网页内容的宽度是否可大于WebView控件的宽度
ws.setLoadWithOverviewMode(false);
// 保存表单数据
ws.setSaveFormData(true);
// 是否应该支持使用其屏幕缩放控件和手势缩放
ws.setSupportZoom(true);
ws.setBuiltInZoomControls(true);
ws.setDisplayZoomControls(false);
// 启动应用缓存
ws.setAppCacheEnabled(true);
// 设置缓存模式
ws.setCacheMode(WebSettings.LOAD_DEFAULT);
// setDefaultZoom api19被弃用
// 设置此属性,可任意比例缩放。
ws.setUseWideViewPort(true);
ws.setLoadWithOverviewMode(true);
// 缩放比例 1
webView.setInitialScale(1);
// 告诉WebView启用JavaScript执行。默认的是false。
// ws.setJavaScriptEnabled(true);
// 页面加载好以后,再放开图片
ws.setBlockNetworkImage(false);
// 使用localStorage则必须打开
ws.setDomStorageEnabled(true);
// 排版适应屏幕
ws.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NARROW_COLUMNS);
// WebView是否支持多个窗口//默认为false,如果设置为true会导致一些H5内部页面跳转不了
// ws.setSupportMultipleWindows(true);
ws.setJavaScriptCanOpenWindowsAutomatically(true);
ws.setAllowContentAccess(true); // 是否可访问Content Provider的资源,默认值 true
ws.setAllowFileAccess(true); // 是否可访问本地文件,默认值 true
// 是否允许通过file url加载的Javascript读取本地文件,默认值 false
ws.setAllowFileAccessFromFileURLs(true);
// 是否允许通过file url加载的Javascript读取全部资源(包括文件,http,https),默认值 false
ws.setAllowUniversalAccessFromFileURLs(true);
// webview从5.0开始默认不允许混合模式,https中不能加载http资源,需要设置开启。
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
ws.setMixedContentMode(android.webkit.WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
}
/* 设置字体默认缩放大小(改变网页字体大小,setTextSize api14被弃用)*/
ws.setTextZoom(100);
//调试WebView需要满足安卓系统版本为Android 4.4+已上。并且需要再你的APP内配置相应的代码
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && BuildConfig.DEBUG) {
WebView.setWebContentsDebuggingEnabled(true);
}
}
}
dolphin_lib-release.aar
请点击下载SDK包:“dolphin_lib-release.aar”
一.将最小编译版本修改为17或者以上,通常在主module(通常名字为“app”)下gradle文件内添加或者修改,如
android {
compileSdkVersion 30
buildToolsVersion "30.0.3"
defaultConfig {
applicationId "com.example.dolphin_sdk_demo"
minSdkVersion 17
targetSdkVersion 30
versionCode 1
versionName "1.0"
}
}
二.项目根节点下的gradle文件内添加如下代码
flatDir {
dirs 'libs'
}
并在allprojects内repositories内添加
maven { url "https://jitpack.io" }
本文档附上具体添加位置如下
allprojects {
repositories {
flatDir {
dirs 'libs'
}
maven { url "https://jitpack.io" }
maven { url 'http://maven.aliyun.com/nexus/content/groups/public/' }
maven { url 'http://maven.aliyun.com/nexus/content/repositories/jcenter' }
maven { url 'http://maven.aliyun.com/nexus/content/repositories/google' }
maven { url 'http://maven.aliyun.com/nexus/content/repositories/gradle-plugin' }
}
}
三.将下载好的本SDK的aar包放到主module下libs目录下,目录索引如图
四.主module下gradle文件内添加依赖以导入aar包,如下
implementation(name: 'dolphin_lib-release', ext: 'aar')
五.除了添加aar包的依赖外,还要添加SDK所需依赖,成功运行SDK需要以下所有依赖,如果本身的项目里已经有其中部分依赖,则保留最新版本而去掉其他低版本
dependencies {
implementation(name: 'dolphin_lib-release', ext: 'aar')
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.2.1'
implementation 'androidx.constraintlayout:constraintlayout:2.0.2'
//Glide
implementation 'com.github.bumptech.glide:glide:4.11.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
implementation 'com.github.bumptech.glide:okhttp3-integration:4.11.0'
//EventBus
implementation 'org.greenrobot:eventbus:3.0.0'
//dagger-rxjava2-retrofit2-okhttp3
implementation 'com.google.dagger:dagger:2.23.2'
annotationProcessor 'com.google.dagger:dagger-compiler:2.23.2'
implementation 'io.reactivex.rxjava2:rxjava:2.2.5'
implementation 'io.reactivex.rxjava2:rxandroid:2.0.2'
implementation 'com.squareup.retrofit2:retrofit:2.6.0'
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.6.0'
implementation 'com.squareup.retrofit2:converter-gson:2.6.0'
implementation 'com.trello.rxlifecycle2:rxlifecycle-android:2.2.2'
implementation 'com.trello.rxlifecycle2:rxlifecycle-components:2.2.2'
implementation 'com.squareup.okhttp3:okhttp:3.12.1'
//单Activity+多Fragment
implementation 'me.yokeyword:fragmentationx:1.0.2'
implementation 'me.yokeyword:fragmentationx-swipeback:1.0.2'
implementation 'me.yokeyword:eventbus-activity-scope:1.1.0'
//WebSocket收发消息
implementation 'org.java-websocket:Java-WebSocket:1.3.6'
api 'com.github.NaikSoftware:StompProtocolAndroid:1.6.4'
}
六.清单配置文件AndroidManifest.xml中添加权限、相关Activity和Service注册以及其他设置,如下:
1.权限(manifest节点下添加,不需要代码动态申请,因为SDK内已经有此类逻辑了)
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- SDCard读写数据权限 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- 系统照相机拍照 -->
<uses-permission android:name="android.permission.CAMERA" />
2.AndroidManifest.xml中application节点设置属性
android:allowBackup="true"
android:requestLegacyExternalStorage="true"
android:supportsRtl="true"
具体位置如下图
3.AndroidManifest.xml中application节点下添加以下代码(SDK所需Activity与Service注册以及其他数据)
<service
android:name="com.yiju.dolphin_lib.service.MsgService"
android:enabled="true"
android:exported="true" />
<activity
android:name="com.yiju.dolphin_lib.pages.activity.SessionActivity"
android:exported="true"
android:launchMode="singleTask"
android:screenOrientation="portrait"
android:theme="@style/Lib_MainActivityTheme"
android:windowSoftInputMode="adjustResize|stateHidden" />
<activity
android:name="com.yiju.dolphin_lib.pages.activity.MediaActivity"
android:launchMode="singleTop"
android:theme="@style/Lib_MediaActivityTheme" />
<activity
android:name="com.yiju.common.crop.CropImageActivity"
android:theme="@style/Theme.MaterialComponents.Light.NoActionBar" />
<!-- 添加使用Apache HTTP client库,兼容安卓P -->
<uses-library
android:name="org.apache.http.legacy"
android:required="false" />
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.android7.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
4.兼容安卓7.0以上uri权限的配置
主module下res目录下添加xml目录,再在xml目录里新增file_paths.xml文件,里面代码如下
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<root-path name="root" path="." />
<!--配置root-path。这样子可以读取到sd卡和一些应用分身的目录,在小米6的手机上微信分身有这个crash-->
<root-path name="root-path" path="" />
<files-path name="files" path="." />
<files-path name="files-path" path="." />
<cache-path name="cache" path="." />
<cache-path name="cache-path" path="." />
<external-path name="external" path="." />
<!--/storage/emulated/0/-->
<external-path name="external_storage_root" path="." />
<!--/storage/emulated/0/Android/data/...-->
<external-files-path name="external_file_path" path="." />
<!--代表app 外部存储区域根目录下的文件 Context.getExternalCacheDir目录下的目录-->
<external-cache-path name="external_cache_path" path="." />
</paths>
清单文件application节点下添加
<provider>
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.android7.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
5.为加载图片的第三方框架Glide添加加载超时的相关设置,首先在主module的包路径下(随便哪个地方都行,只需要能被清单文件引用到就行)创建一个继承com.bumptech.glide.module.AppGlideModule的类FlickrGlideModule,代码如下,创建之后复制粘贴即可,复制粘贴后爆红需要重新alt+enter重新导包
**
* 重点:这样的类在一个项目里只能有一个,多余的要删掉,不然会运行时报错
* 此类需要在主module的gradle中导入相关依赖包如
* annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
* 否则会扫描不到注解
*/
@GlideModule
public class FlickrGlideModule extends AppGlideModule {
@Override
public void applyOptions(Context context, GlideBuilder builder) {
super.applyOptions(context, builder);
}
@Override
public void registerComponents(Context context, Glide glide, Registry registry) {
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.connectTimeout(60, TimeUnit.SECONDS)
.writeTimeout(60, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS)
.build();
registry.replace(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory(okHttpClient));
}
// 关闭扫描清单文件
@Override
public boolean isManifestParsingEnabled() {
return false;
}
}
然后在AndroidManifest.xml中application节点下添加数据如下
<!-- 处理Glide加载链接超时 -->
<meta-data android:name="com.example.dolphin_sdk_demo.FlickrGlideModule" android:value="GlideModule" />
其中com.example.dolphin_sdk_demo.FlickrGlideModule需要替换成刚刚创建的类的全路径名称。
七.如果项目采用了混淆,则还需要在混淆文件(主module下proguard-rules.pro文件)中添加以下混淆代码(因为引用了许多其他第三方库,所以混淆有点多;如果出现警告提示,不用管,因为是警告混淆可能不存在的类路径)
#设置混淆的压缩比率 0 ~ 7
-optimizationpasses 5
#包名不混合大小写
-dontusemixedcaseclassnames
#混淆时是否记录日志
-verbose
#优化 不优化输入的类文件
-dontoptimize
#混淆采用的算法.
-optimizations !code/simplification/arithmetic,!field/,!class/merging/
#忽略警告
-ignorewarnings
-keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,*Annotation*,EnclosingMethod
#避免混淆泛型 如果混淆报错建议关掉
-keepattributes Signature
#保护注解
-keepattributes *Annotation*
-keepattributes EnclosingMethod
# Gson specific classes
-dontwarn com.google.gson.**
-dontwarn sun.misc.**
-keep class sun.misc.Unsafe { *; }
-keep class com.google.gson.stream.** { *; }
-keep class com.google.gson.** { *;}
# Application classes that will be serialized/deserialized over Gson
#保留一个完整的包
-keep class com.yiju.dolphin_lib.http.model.** { *; }
-keep class com.yiju.dolphin_lib.http.model.base.** { *; }
-keep class com.yiju.common.retrofit_rx.** { *; }
-keep class com.yiju.common.fragment.** { *; }
##---------------End: proguard configuration for Gson ----------
-keepattributes *JavascriptInterface*
#所有activity的子类不要去混淆
-keep public class * extends android.app.Fragment
-keep public class * extends android.support.v7.app.FragmentActivity
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
#如果引用了v4或者v7包
-keep public class * extends android.support.v4.**
-keep public class com.android.vending.licensing.ILicensingService
-keep class android.support.v4.**{*;}
-keep class android.support.v7.**{*;}
-dontwarn android.support.**
-dontwarn android.annotation
-keep class org.apache.http.**{*;}
##混淆前后的映射
-printmapping mapping.txt
-keep class android.support.** {*;}
-keep class org.apache.commons.** {*;}
-keep class org.apache.http.** {*;}
-keep class pub.devrel.easypermissions.** {*;}
-keep class retrofit_rx.** {*;}
#所有native的方法不能去混淆.
-keepclasseswithmembernames class * {
native <methods>
}
#保持自定义控件类不被混淆
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet);
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet, int);
}
-keepclassmembers class * extends android.app.Activity {
public void *(android.view.View);
}
#保持Parcelable不被混淆
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
#保持 Serializable 不被混淆
-keepnames class * implements java.io.Serializable
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
private static final java.io.ObjectStreamField[] serialPersistentFields;
!static !transient <fields>;
!private <fields>;
!private <methods>;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
#保持枚举 enum 类不被混淆 如果混淆报错,建议直接使用上面的 -keepclassmembers class * implements java.io.Serializable即可
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keepattributes *Annotation*
-keepclassmembers class ** {
@org.greenrobot.eventbus.Subscribe <methods>;
}
-keep enum org.greenrobot.eventbus.ThreadMode { *; }
-keep class org.greenrobot.eventbus.** { *; }
#不混淆资源类
-keepclassmembers class **.R$* {
public static <fields>;
}
-keep class me.yokeyword.fragmentation.** { *; }
-dontusemixedcaseclassnames
-dontshrink
-dontoptimize
-dontwarn com.google.android.maps.**
-keep public class javax.**
-dontwarn android.support.v4.**
-keepattributes Exceptions,InnerClasses,Signature
-keepattributes *Annotation*
-keepattributes SourceFile,LineNumberTable
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keepnames class * implements android.os.Parcelable {
public static final ** CREATOR;
}
# Retrofit, OkHttp, Gson
-keepattributes *Annotation*
-keepattributes Signature
-keep class com.squareup.okhttp.** { *; }
-keep interface com.squareup.okhttp.** { *; }
-dontwarn com.squareup.okhttp.**
-dontwarn rx.**
# Retrofit 2.X
-dontwarn retrofit2.**
-keep class retrofit2.** { *; }
-keepattributes Signature
-keepattributes Exceptions
-keepclasseswithmembers class * {
@retrofit2.http.* <methods>;
}
# OkHttp3
-keepattributes Signature
-keepattributes *Annotation*
-keep class okhttp3.** { *; }
-keep interface okhttp3.** { *; }
-dontwarn okhttp3.**
-keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* {
long producerIndex;
long consumerIndex;
}
-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef {
rx.internal.util.atomic.LinkedQueueNode producerNode;
}
-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueConsumerNodeRef {
rx.internal.util.atomic.LinkedQueueNode consumerNode;
}
-dontwarn io.reactivex.**
-keep class io.reactivex.** { *; }
-dontnote rx.internal.util.PlatformDependent
-dontwarn rx.Single
-dontwarn rx.Observable
-keepnames class rx.Single
-keepnames class rx.Observable
-keep class **$$ViewBinder { *; }
-keepclasseswithmembernames class * {
@butterknife.* <fields>;
}
-keepclasseswithmembernames class * {
@butterknife.* <methods>;
}
-keep class androidx.** {*;}
-keep public class * extends androidx.**
-keep interface androidx.** {*;}
-dontwarn androidx.**
#处理Glide加载链接超时start
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public class * extends com.bumptech.glide.module.AppGlideModule
-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
**[] $VALUES;
public *;
}
-keep class com.bumptech.glide.GeneratedAppGlideModuleImpl
#处理Glide加载链接超时end
八.如果启用了资源压缩,则需要在主module下的res/raw目录下的keep.xml文件(如果没有则创建)内keep属性的值字符串里添加@drawable/lib_emoji_*,与已有的其他需要保留的资源名以英文逗号(千万别是中文逗号)分隔,具体如下
<?xml version="1.0" encoding="utf-8"?>
<resources
xmlns:tools="http://schemas.android.com/tools"
tools:keep="@layout/getui_notification,
@drawable/push,
@drawable/push_small,
@drawable/lib_emoji_*"/>
九.如何使用此SDK如果前面的几点都已完成,那么可以使用下面的代码进行初始化和跳转操作了
//初始化SDK,多次初始化无效,始终以第一次为准
//参数一是上下文context,参数二是你在海豚客服申请的appId
AppSession.init(getApplicationContext(), "你在海豚客服申请的appId");
//跳转到对话窗口页面,参数为当前Activity
AppSession.getInstance().startSessionActivity(MainActivity.this);
十.常见问题
1.如果发现SDK的UI错误或者异常,可能是因为工程主module下的资源文件(布局文件、图片、文字、大小)命名与SDK中重名了,重名即意味着SDK资源被覆盖掉了。
2.如果发现项目从谷歌上导包缓慢,可以在根目录下的grade文件中buildscript内repositories内添加以下代码改为从阿里云镜像获取
maven { url 'http://maven.aliyun.com/nexus/content/groups/public/' }
maven { url 'http://maven.aliyun.com/nexus/content/repositories/jcenter' }
maven { url 'http://maven.aliyun.com/nexus/content/repositories/google' }
maven { url 'http://maven.aliyun.com/nexus/content/repositories/gradle-plugin' }
allprojects内repositories内添加
maven { url "https://jitpack.io" }
maven { url 'http://maven.aliyun.com/nexus/content/groups/public/' }
maven { url 'http://maven.aliyun.com/nexus/content/repositories/jcenter' }
maven { url 'http://maven.aliyun.com/nexus/content/repositories/google' }
maven { url 'http://maven.aliyun.com/nexus/content/repositories/gradle-plugin' }
选择【系统接入】-【APP】-【新增渠道】
设置【新增渠道--渠道名称--确定】,部署配置,复制链接,并由APP开发工作人员在APP上进行配置。
1、新建一个viewController类,导入头文件WebKit,在viewDidLoad方法中添加webView,地址指向海豚客服的h5页面。
#import "ViewController.h"
#import <WebKit/WebKit.h>
@interface ViewController() <WKNavigationDelegate>
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
WKWebView *webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:configuration];
webView.navigationDelegate = self;
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://h5chat.17j.club/#/chat?appId=h5000001"]]];
[self.view addSubview:webView];
}
#pragma mark - WKNavigationDelegate
- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler {
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
NSURLCredential *credential = [[NSURLCredential alloc] initWithTrust:challenge.protectionSpace.serverTrust];
completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
}
}
@end
import UIKit
import WebKit
class ViewController: UIViewController, WKNavigationDelegate {
override func viewDidLoad() {
super.viewDidLoad()
let configuration = WKWebViewConfiguration()
let webView = WKWebView(frame: view.bounds, configuration: configuration)
webView.navigationDelegate = self;
webView.load(URLRequest(url: URL(string: "https://h5chat.17j.club/#/chat?appId=h5000001")!))
view.addSubview(webView)
}
func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
let credential = URLCredential(trust: challenge.protectionSpace.serverTrust!)
completionHandler(.useCredential, credential)
}
}
}
2、在工程info.plist文件中,增加隐私权限:
Privacy - Camera Usage Description 需要访问您的相机
Privacy - Photo Library Usage Description 需要访问您的相册
Privacy - Photo Library Additions Usage Description 需要访问您的相册
1.打开海豚客服系统后台,选择【设置】-【系统接入】-【抖音接入】-【新增渠道】
设置【新增渠道】-- 【渠道名称(必填项)】--【确定】
弹出抖音APP授权二维码,使用抖音APP,打开首页【搜索】-【扫一扫】扫码进行授权
授权完成之后打开右上角“在线工作台”即可收发消息。
微博接入,请联系在线客服人员
请点击官网【首页】-【帮助】-【客服入口设置】进行查看
1.如何使用微信端原生对话框?
在微信公众平台里设置自定义菜单,设置文字消息,引导客户用原生页面进行问答。
2.公众号接入海豚客服和微信原生客服有什么不同
开通海豚客服账号之后,在第三方客服系统管理后台进行微信授权即可接入使用。海豚客服客服系统提供了使用微信聊天界面和H5页面客服两种方式供使用者选择。即企业可以直接用公众号的聊天框作为客服聊天窗,也可以在菜单中添加客服按钮,然后跳转到一个H5聊天窗口。
3.为什么微信公众号或小程序接入成功之后还是无法在海豚客服工作台上收到消息?
登录微信公众号、小程序的管理后台,查看是否有接入第三方智能客服,如有,需要取消第三方授权。
4.个人公众号或未通过认证的微信公众号可以授权海豚客服接入吗?
答:微信不允许这类公众号接入海豚客服。只有认证过的企业公众号可以接入海豚客服。
5.为什么在海豚客服工作台的客户资料栏,无法看到咨询者的昵称?
答:正常情况下,海豚客服可以获取用户的微信openid,微信昵称(仅认证公众号),头像(仅认证公众号),所以,如果您的公众号是个人号或未通过微信认证的公众号,则我们只能获取到用户的微信openid,并以此作为用户名
1.网页端如何关闭会话窗口自动弹出功能?
选择【系统接入】-【网站】点击需要修改渠道进行【部署配置】,复制粘贴代码,此代码默认会话窗口主动弹出,如需关闭自动弹出功能,需要将粘贴后的代码进行以下更改
1.管理员如何添加多个客服账号
因客服工作的需求,系统后台需要有管理员及多个客服身份进行服务,进入海豚客服管理后台->账号管理-->新增客服,这里可以添加多个客服账号及设置客服的身份。
2.坐席数是什么意思?
坐席数指企业可为客户提供服务的窗口数。例如,小明的企业有 9位客服人员,通过 3 班倒的方式为客户提供 7 * 24 小时的在线客服,同一时间有 3位客服人员通过海豚客服为客户服务,那么小明购买 3 个坐席就足够使用了,而客服帐号可以创建 9 个,每位客服人员都有自己的帐号。
3.管理员怎么删除客服信息
管理员暂不支持删除账号信息,可以设置停用。
在线工作台是客服人员进行收发消息的主要操作台。访客和客服的在线聊天沟通平台。所有已接入的渠道消息都可以在此工作台进行应答。
1.客户聊天工作台;
2.同事聊天工作台;
a.客户消息:红色数字标志分别实时显示客户、同事未读消息总数;
b.客户消息列表:包含当前未处理客户对话和历史客户对话。选择其中某个客户,点击鼠标右键,可设置会话完成,置顶当前客户及删除此客户会话列表;
3. 客户名称:默认显示名称为当前渠道来源+编号组成或者微信昵称(微信客户);
4.所属公司名称:显示客服所属公司;
5.邀请接入:邀请同事加入当前聊天;
6.被邀请客服:被同事邀请接入客户会话;
7.邀请接入客服头像;
8.邀请接入客服列表;
9.会话完成:客服接待完毕,点击完成会话;
10.更多功能:
置顶/取消置顶:将当前客户会话选择置顶或者取消置顶。
删除:从会话列表中删除该条聊天记录,不影响继续接收消息及历史会话记录。
11.会话输入框:支持发送图片、文字、文件、表情;
12.客户信息:填写客户反馈过来的姓名、电话、微信等基本信息;
13.快捷回复:添加快捷回复,一键复制粘贴;
14.历史渠道来源;
15.历史会话记录:显示时间和内容;
16.关联绑定客户信息。
在【在线工作台】将客户信息进行保存,可在【客户管理】里查找保存之后的用户信息。
点击【查看详情】,可查看用户基本信息,历史会话记录等。
1.可以看到哪些数据
根据时间和渠道来源进行筛选,展示某时间段某渠道的总客户化、新老客户数及比值、机器人接入量、人工接入量。机器人反馈量,人工反馈量。
1.怎么修改客服头像
点击海豚客服管理后台右上角头像部分,如下:
姓名:角色姓名可修改
昵称:角色昵称可修改,必填项,要求15字符以内;
头像:客服可选择图片上传,上传格式JPG、PNG、图片小于1MB。
修改成功后点击【确定】按钮提交。
2.如何修改密码
账户:当前账户信息不支持填写,由系统自动识别;
发送验证码:填写正确验证码;
设置密码:请输入6-12位同时包含字母数字的密码;
确认密码:和【设置密码】所填写密码必须保持一致;
直接点击【确定】提交,即修改密码成功。如需取消修改密码,点击【取消】按钮。
3.初始密码是多少?
手机号码后六位
4.头像还有名称等效果可以自己修改吗?
暂不支持自己修改,可联系我们进行修改。
1.为什么网页客服对话框输入时,无法拼写汉字,只能发送字母?/ 为什么出现页面排版错乱,只有图片和文字?
1.建议把浏览器进行升级,使用最新版本浏览器;
2.或者使用谷歌、火狐、360极速浏览器等浏览器;
3.清除浏览器缓存进行尝试。
使用过程中出现如下图“请使用浏览器”打开的提示,可进行以下操作
选择【系统接入】-【网站】-【新增渠道】设置【新增渠道--渠道名称--确定】,选择【下载源码】,将源码下来下载之后自行配置到自己域名的网站之上,再将配置自己公司域名的连接发送给客户即可,访问源码index.html需带上参数,参数为下图_ht()括号中链接,取index.html后面#开始到最后(包含#号)。
以网站为例,打开海豚客服后台,点击 【客服接入】- 【网站】 -【编辑】-即可填写自己的个性昵称设置自定义头像、昵称、窗口标题和窗口背景颜色。目前链接/二维码,app渠道仅仅支持修改客服头像和昵称。
选择【系统接入】-【网站】-【新增渠道】设置【新增渠道--渠道名称--确定】,部署配置,复制链接,并由前端开发人员进行网站配置。
在下载的代码里加上“&uName=xxx”
1.手机APP怎么下载?
安卓在手机应用市场下载,苹果手机在App Store下载
2.海豚客服APP怎么无法注册
需要打开网站www.17j.club进行注册和系统接入才能试用海豚客服APP
点击【在线工作台】--【快捷回复】可设置快捷回复
电脑设置消息提示音方式如下
点击【在线工作台】- 【头像】- 【静音/取消静音】。消息提示音默认是开启状态。
请联系在线客服进行开通。
点击【设置】-【会话设置】可设置欢迎语及常见问题。
1.起售付费方案是什么?
安卓去手机应用市场下载,苹果手机去App Store下载
2.有没有培训服务?
海豚客服产品极易上手,无需专门培训即可开始使用,我们仍会提供关于海豚客服具体使用方法,可上门或远程任选。
3.数据在你们这里安全吗?
非常安全,我们对整个系统部署了银行级的 SSL 加密访问功能,保证了数据在网络上传输的安全。在服务器端有周密的实时备份方案,保证数据不会丢失。服务器由安全专家把护,拥有强壮的 DDos 防护和入侵防护能力。
4.体验版以后可以升级吗?
体验版可以随时升级到各收费版本,你的账户数据在升级中不会有任何损失。升级可三分钟自助完成,即升即用。
5.需要签一大堆合同吗?
不需要。你只需要在注册账户前阅读并同意《海豚客服服务条款》即可。当然,如果你需要的话,海豚客服会提供完整的纸质版合同。
6.怎么付钱,可以提供发票吗?
我们支持支付宝和微信在线付款,付款后可以直接在线索取发票,我们提供正规的增值税普通发票,并会按照你提供的地址顺丰快递过去,包运费。
7.微信公众号找人工客服
1、在公众号对话框直接输入:转人工 | 人工客服等关键字,对话转到人工客服服务; 2、可在微信自定义菜单里,添加 “ 人工客服 ” 入口,点击菜单,直接进入人工服务。
8.如何收费?
价格信息请点击:https://www.17j.club/price.html,进行查看。
9.你们的微信公众号
1.微信搜索“海豚应答”
2.微信扫码关注
在线咨询
电话咨询
关注我们
免费试用
返回顶部