本项目演示了如何调用凡泰极客Swan SDK快速构建一个金服宝客户端和员工端。

penganfu 06f3cbf73d update readme 2 years ago
.idea 129e8e326b specify version 3.4.15-swan-662 2 years ago
app 129e8e326b specify version 3.4.15-swan-662 2 years ago
gradle 68580cb0c1 specify version 2 years ago
.gitignore df5efd2401 git ignore 2 years ago
README.md 06f3cbf73d update readme 2 years ago
build.gradle 129e8e326b specify version 3.4.15-swan-662 2 years ago
config.gradle 129e8e326b specify version 3.4.15-swan-662 2 years ago
fino_debug.jks 537bbf5bc1 first commit 2 years ago
gradle.properties 537bbf5bc1 first commit 2 years ago
gradlew 537bbf5bc1 first commit 2 years ago
gradlew.bat 537bbf5bc1 first commit 2 years ago
settings.gradle 537bbf5bc1 first commit 2 years ago
swan-andorid-demo.iml 537bbf5bc1 first commit 2 years ago

README.md

集成 Android SDK 前的准备工作

注册申请凡泰极客开发者账号,申请AppId,AppKey

详细请咨询相关接口人。

Android SDK 介绍及导入

Android SDK 介绍

FinoChat SDK 为用户开发 IM 相关的应用提供的一套完善的开发框架。包括以下几个部分:

  • SDK_Core: 为核心的消息协议实现,完成与服务器之间的信息交换。
  • SDK: 是基于核心协议实现的完整的 IM 功能,实现了不同类型消息的收发、会话管理、群组、好友、聊天室等功能。
  • HttpEngine: H5资源加速服务组件
  • ConvoUI: 会话型UI交互组件
  • FinoChatClient: 是 SDK 的入口,主要完成初始化等功能,也是获取其他模块的入口。
    • AccountApi: 负责账户管理相关功能,包括登入、登出等。
    • ContacApi: 负责好友的添加删除,黑名单的管理。
    • GroupApi: 负责群组的管理,创建、删除群组,管理群组成员等功能。
    • ChatRoomApi: 负责聊天室的管理。
    • UIApi: 是一组 IM 相关的 UI 控件,旨在帮助开发者快速集成FinoChat SDK。
      • ChatUI: 消息聊天界面UI
      • ConversationUI: 会话列表UI
      • MineUI: “我”的信息UI
      • ContactUI: 通讯录UI

集成 Android SDK

在您阅读此文档时,我们假定您已经具备了基础的 Android 应用开发经验,并能够理解相关基础概念,SDK支持Android 4.4及以上版本。

手动导入 SDK

您可以到凡泰极客官网下载FinoChat SDK。

到此您已经下载好了 SDK,下面开始学习 SDK 的集成使用吧!

SDK 目录讲解

从官网上下载下来的包中分为如下五部分:

  • 凡泰极客 Android FinoChatSDK 开发使用
  • 凡泰极客 Android doc SDK 相关API文档
  • 凡泰极客 Android FinoChatAppDemo 工程源码 具体接口讲解请转到 Api Docs。

第三方库介绍

FinoChatUI 中用到的第三方库:

  • PhotoView: 图片处理库,浏览显示
  • Glide: 用于页面刷新
  • RxJava: 响应式框架

配置工程

配置仓库地址

在项目的顶层build.gradle中配置如下

allprojects {
    repositories {
        google()
        jcenter()
        maven { url "https://jitpack.io" }
        maven {
            url "https://gradle.finogeeks.club/repository/finogeeks/"
            credentials {
                username "gradle"
                password "ftjk@@123321"
            }
        }
        maven { url "https://dl.bintray.com/drummer-aidan/maven" }
    }
}

添加依赖库

FinoChat Android sdk可以直接通过gradle添加依赖集成:

dependencies {
	//finochatsdk 版本号替换为自己要使用的版本
	implementation “com.finogeeks.finochat.sdk:finochatsdk:latest.release”
    //音视频通话模块 可选配置 不需要可以不添加
    implementation “com.finogeeks.finochat.sdk:finovideochat:latest.release”
}

编译工程

以上步骤进行完后,编译工程。如果没有报错,恭喜你,集成 SDK 成功,可以进行下一步了。

Android SDK使用

接口文档

请参考APIDoc

使用指引

SDK在集成及导入后接下来就可以使用了。

第一步:创建配置选项

要求在 application 的oncreate方法中做初始化,初始化的时候需要传入设置好的 options。

FinoChatOptions options = new FinoChatOptions();
options.setAppKey(“appKey”);
options.setAppType(“appType”);
options.setAppId("3");
options.setApiPrefix("/api/v1");
options.setNotificationIcon(R.drawable.login_logo);// 后台运行的icon
options.setNotificationSubtitle(“正在后台运行”) // 后台运行的文案
options.setThemeId(R.style.ChatTheme);//主题配置 可选
options.setAppDebug(BuildConfig.DEBUG);//是否是debug模式 必须设置
options.setSdkVersion(BuildConfig.VERSION_NAME);//设置页面展示的应用版本号
options.setSettings(new HashMap<String, Object>() {
    	  {   //一些额外的配置选项 参见api文档
    	    put("isWatermarkChangeable", true);
    	    put("dispatchMode", "B");
    	  }
});

第二步:初始化

sdk初始化入口主要是对sdk部分配置的初始化和session的初始化:

        FinoChatOption options = new FinoChatOption();
        options.setLogLevel(android.util.Log.VERBOSE);
        options.setAppKey(BuildConfig.KEY);
        options.setAppType(BuildConfig.AppType);

        if (!apiUrl.isEmpty()) {
            options.setApiURL(apiUrl);
        } else {
            options.setApiURL(BuildConfig.API);
        }
        options.setAppId("3");
        options.setApiPrefix("/api/v1");

        // 通知栏图标
        options.getNotification().notificationIcon = R.drawable.notification;

        options.setAppDebug(BuildConfig.DEBUG);
        options.setSdkVersion(com.finogeeks.finochat.BuildConfig.VERSION_NAME);


        // 配置微信APPID
        FinoChatOption.ShareParams shareParams = new FinoChatOption.ShareParams(BuildConfig.WECHAT_APPID, BuildConfig.MINIPROGRAM_ID, R.mipmap.ic_launcher);
        options.setShareParams(shareParams);
        ...

注意:如果用户未登录,不会进行session初始化,同时不会回调onSuccess或onError,所以用户需要在启动页或初始化时通过FinoChatClient.getInstance().accountManager().isLogin()先判断是否为登录状态,如果是未登录状态,则应该跳转到登录页面或执行登录操作,登录成功后sdk会自动执行session的初始化。示例:

//在闪屏页判断
if (!FinoChatClient.getInstance().accountManager().isLogin()) {
    startActivity(new Intent(this, LoginActivity.class));
    finish();
} else if (FinoChatClient.getInstance().isSessionInitSuccess()) {
	finish();
}

第三步: 用户登录

FinoChatClient.getInstance().accountManager().login(username, password, new FinoCallBack<Map<String, Object>>() {//回调
    @Override
    public void onSuccess(Map<String, Object> result) {
    	finish();
    }
    @Override
    public void onProgress(int progress, String status) {
        startActivity(new Intent(LoginActivity.this, SplashActivity.class));
        finish();
    }
    @Override
    public void onError(int code, String message) {
        Log.d("LoginActivity", message);
        Toast.makeText(LoginActivity.this, message, Toast.LENGTH_LONG).show();
    }
});

登录成功后会自动初始化session,同时sdk还会提供有token的登录接口。

主页面搭建

为了提供灵活的页面配置,sdk没有提供默认主页面,而是提供了对应的Fragment供用户自由组装,其中包括“会话“页面、”通讯录“页面和”我的“页面。开发者可以通过FinoChatClient.getInstance().chatUIManager().conversationFragment()获取对应的Fragment组装主页面。

主要API接口

sdk对外暴露的API接口主要在com.finogeeks.finochat.sdk包中:

  • FinoChatClient :客户端主要入口,提供初始化接口和获取其他服务;
  • IAccountManager:账户相关接口,包括登录 注销 登录状态判断等;
  • IChatUiManager:UI相关接口,用户获取一些Fragment以及启动一些页面或对话框;
  • INotificationManager:sdk事件通知接口,可以用于监听sdk内部事件 如退出登录然后执行自己的操作;
  • IPluginManager : 一些UI定制的接口 例如可以在聊天页面更多菜单里注册自己的选项并获取事件监听 也可以定制我的页面的项目;

金服宝接入

金服宝分为两个端,一个是用于客户发起咨询的客户端,另一个是用于员工服务客户,处理工单的员工端,可以统一于一个项目中,也可以分开为两个项目,我们提供的demo是合在一个项目里的。可自行选择;

sdk初始化

在Applicaion里的onCreate()里进行初始化操作,示例如下。

        FinoChatOption options = new FinoChatOption();
        options.setLogLevel(android.util.Log.VERBOSE);
        options.setAppKey(BuildConfig.KEY);
        options.setAppType(BuildConfig.AppType);

        if (!apiUrl.isEmpty()) {
            options.setApiURL(apiUrl);
        } else {
            options.setApiURL(BuildConfig.API);
        }
        options.setAppId("3");
        options.setApiPrefix("/api/v1");

        // 通知栏图标
        options.getNotification().notificationIcon = R.drawable.notification;

        options.setAppDebug(BuildConfig.DEBUG);
        options.setSdkVersion(com.finogeeks.finochat.BuildConfig.VERSION_NAME);


        // 配置微信APPID
        FinoChatOption.ShareParams shareParams = new FinoChatOption.ShareParams(BuildConfig.WECHAT_APPID, BuildConfig.MINIPROGRAM_ID, R.mipmap.ic_launcher);
        options.setShareParams(shareParams);

        // 金管家小程序配置
        FinoChatOption.IShareWxAppletCallback shareJgj = () -> {
            FinoChatOption.ShareAppletParams shareJgjWxParams = new FinoChatOption.ShareAppletParams();
            String fcid = ServiceFactory.getInstance().getSessionManager().getCurrentSession().getMyUserId();
            shareJgjWxParams.miniProgramId = BuildConfig.JGJ_MINIPROGRAM_ID;
            shareJgjWxParams.path = String.format("pages/home/home?fcid=%s", fcid);
            shareJgjWxParams.title = "凡泰金管家";
            shareJgjWxParams.name = "凡泰金管家";
            shareJgjWxParams.description ="您身边的服务专家";
            shareJgjWxParams.type = BuildConfig.ENV_VERSION;
            shareJgjWxParams.shareType = "STUDIO";
            shareJgjWxParams.icon = BitmapFactory.decodeResource(getResources(), R.drawable.jinguanjia_cover);
            shareJgjWxParams.poster = R.drawable.turkey_jfb_share_poster;
            return shareJgjWxParams;
        };

        // 金易联小程序配置
        FinoChatOption.IShareWxAppletCallback shareJyl = () -> {
            FinoChatOption.ShareAppletParams shareJylWxParams = new FinoChatOption.ShareAppletParams();
            String fcid = ServiceFactory.getInstance().getSessionManager().getCurrentSession().getMyUserId();
            shareJylWxParams.miniProgramId = BuildConfig.MINIPROGRAM_ID;
            JsonObject jsonObject = new JsonObject();
            jsonObject.addProperty("advisorId", fcid);
            String url = URLEncoder.encode(jsonObject.toString());
            shareJylWxParams.path = String.format("pages/login/index?type=BIND_ADVISOR&value=%s", url);
            shareJylWxParams.title = "凡泰金易联";
            shareJylWxParams.name = "凡泰金易联";
            shareJylWxParams.description = "您身边的服务专家";
            shareJylWxParams.type = BuildConfig.ENV_VERSION;
            shareJylWxParams.shareType = "SWAN_IM";
            shareJylWxParams.icon = BitmapFactory.decodeResource(getResources(), R.drawable.jyl_cover);
            shareJylWxParams.poster = R.drawable.turkey_jfb_share_poster;
            return shareJylWxParams;
        };

        // 配置小程序
        Map<String, FinoChatOption.IShareWxAppletCallback> applets = new HashMap<>();
        applets.put("凡泰金管家", shareJgj);
        applets.put("凡泰金易联", shareJyl);
        options.swan.shareAppletParams = applets;

        options.swan.consultHint = "凡泰金易联随时为您服务,请选择您要咨询的业务范围";
        if (!getPackageName().contains(".cloud")) {
            options.swan.templateParams.practiceNo = "员工编号";
            options.swan.templateParams.department = "网点";
            options.swan.templateParams.telephone = "网点电话";
            options.swan.templateParams.duration = false;
        }

        options.swan.isSwanCloud = getPackageName().contains(".cloud");
        options.swan.dispatchMode = "B";
        options.swan.signIn = false;


        options.getSettings().apm = false;
        options.getSettings().feedback = true;
        options.getSettings().isHideSecurityNetDisk = false;


        options.channel.supportChannelType = "private";
        options.channel.channelWechatQrCode = true;

        options.watermark.isWatermarkChangeable = true;
        options.watermark.isWatermarkEnable = false;

        options.roomMenu.businessCard = false;

        options.chat.isVideoChatGroup = false;
        options.chat.isVideoChatPrivate = false;
        options.chat.convUiHyperTextLines = 0;

        FinoChatOption.Mine mine = new FinoChatOption.Mine();

        if (getPackageName().contains(".cloud")) {
            options.roomMenu.invite = false;

            options.homeMoreMenu.isCreateGroupByTag = false;
            options.homeMoreMenu.isAddFriend = false;
            options.homeMoreMenu.isGroupChat = true;

            options.swan.shareApplet = true;

            mine.isNicknameChangeable = false;

            options.getSettings().apm = true;
        }

        FinoChatClient.getInstance().initFinoChatSession(this, options, new FinoCallBack<Void>() {
            @Override
            public void onSuccess(Void result) {
                Log.i(LOG_TAG, "init success");
            }

            @Override
            public void onProgress(int progress, String status) {
            }

            @Override
            public void onError(int code, String message) {
                Log.e(LOG_TAG, "code:" + code + message);
                if (code != FinoError.NO_HISTORY_TOKEN_FOUND)
                    new Handler(Looper.getMainLooper())
                            .post(() -> ToastsKt.toast(FinoChatApplication.this, "code:" + code + ",message:" + message));
            }
        });

        // 监听登出操作
        FinoChatClient.getInstance().getNotificationManager().addObserver(INotificationManager.EVENT_LOGOUT, (s, map) -> {
            Intent i = getPackageManager().getLaunchIntentForPackage(getPackageName());
            if (i != null) {
                i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                        | Intent.FLAG_ACTIVITY_CLEAR_TASK
                        | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
                startActivity(i);
            }
        });

主题配置示例

1.在styles.xml里自定义主题

    <style name="Theme_ICBC_GOLD">
        <item name="TP_color_normal">#A6844F</item>//主题色普通态

        <item name="TP_color_pressed">#584529</item>//主题色点击态

        <item name="TP_color_disable">#D2C1A7</item>//主题色不可点击态

        <item name="Bubble_Host_solid_color">#FFF5E7</item>//本方气泡填充

        <item name="Bubble_Host_stroke_color">#E4DACA</item>//本方气泡描边

        <item name="Bubble_Guest_solid_color">#FFFFFF</item>//对方气泡填充

        <item name="Bubble_Guest_stroke_color">#CFCFCF</item>//对方气泡描边

        <item name="button_solid_normal">#A6844F</item>//Btn普通态填充

        <item name="button_solid_pressed">#584529</item>//Btn点击态填充

        <item name="button_solid_disable">#D2C1A7</item>//Btn不可点击填充


        <item name="NAV_color">#FAFAFA</item>//Toolbar背景色

        <item name="NAV_TP_color_normal">#A6844F</item>//Toolbar切图/文字普通态(包括调用系统的返回箭头)

        <item name="NAV_TP_color_pressed">#584529</item>//Toolbar切图/文字点击态(包括调用系统的返回箭头)

        <item name="NAV_TP_color_disable">#D2C1A7</item>//Toolbar切图/文字不可点击态(包括调用系统的返回箭头)

        <item name="NAV_title_color">#333333</item>//Toolbar标题文字颜色

        <item name="NAV_line">#B0B0B0</item>//Toolbar分割线颜色


        <item name="switch_solid_enable_off">#FFFFFF</item>//开关可操作_关闭

        <item name="switch_solid_enable_on">#A6844F</item>//开关可操作_打开

        <item name="switch_solid_disable_off">#FFFFFF</item>//开关不可操作_关闭

        <item name="switch_solid_disable_on">#D2C1A7</item>//开关不可操作_打开
    </style>

2.代码配置;

        Map themeMap = new LinkedHashMap();
        themeMap.put("热情红", R.style.Theme_ICBC_Red);
        themeMap.put("高雅金", R.style.Theme_ICBC_GOLD);
        options.setThemeMap(themeMap);

客户端接入

build.gradle配置示例如下:

其中API为配置的服务器地址,AppType为“RETAIL”表示为客户端。KEY是由凡泰签发给app的相关开关配置。

        cloudcus {
            dimension "default"
            applicationId getApplicationIdPrefix() + ".cloud.cus"
            resValue "string", "app_name", "金易联"
            buildConfigField "String", "API", "\"https://mini.finogeeks.club\""
            buildConfigField "String", "KEY", "\"3Z7dQqy0+YqVigRWkVribyJU22ARzISXW6/h6Ys0sBxde0SYn1ea2hbtccCLupvgxpc8BHezyaia4e9+fxQp9PvAn7WIbV+cHWKbbl0sRIyJJbYZ5Gri+ifdk4Ovo8xTn+oF7giS4Trj9l0Mk57V1IklthnkauL6J92Tg6+jzFNUMfyp3K+TupjFkmtnkYmQoA==\""
            buildConfigField "String", "AppType", "\"RETAIL\""

            buildConfigField "String", "WECHAT_APPID", "\"wx3bfb3f78b4ade165\""
            buildConfigField "String", "ENV_VERSION", "\"release\""

            resValue "string", "app_scheme", "jfbcustcloud"
            resValue "drawable", "app_icon", "@mipmap/ic_launcher_cus"

            manifestPlaceholders = [amap_api_key: "72156b499ee055768f29fd857a494af6",
                                    app_icon    : "@mipmap/ic_launcher_cus"]

        }

页面组装

客户端页面包括,会话页面和我的页面,通过Fragment的形式以供组装:

// 会话页面
FinoChatClient.getInstance().chatUIManager().conversationFragment(),
// 我的页面
ARouter.getInstance().navigation(CustomerService.class).retailFragment()

特别注意

客户端的登录分为三级,分别是游客,手机账号和交易账号登录,我们一般会在闪屏页做一次匿名登录以完成sdk的初始化

private void loginGuest() {
        // 登录游客账号
        FinoChatClient.getInstance().accountManager().login(RetailAccountHelper.Companion.getAndroidId(this.getApplicationContext()), RetailAccountHelper.Companion.getDeviceIdPassword(), RetailAccountHelper.Companion.getACCOUNT_LEVEL_DEVICE(), new FinoCallBack<Map<String, Object>>() {
            @Override
            public void onSuccess(Map<String, Object> result) {
                startActivity(new Intent(SplashActivity.this, HomeActivity.class));
                finish();
            }

            @Override
            public void onError(int progress, String status) {
                Toast.makeText(SplashActivity.this, status, Toast.LENGTH_LONG).show();
            }

            @Override
            public void onProgress(int code, String message) {
            }
        });
    }
手机账号登录:

RetailAccountHelper.loginAcitivityLevel = RetailAccountHelper.ACCOUNT_LEVEL_PHONE
FinoChatClient.getInstance().accountManager().login(username, password, RetailAccountHelper.ACCOUNT_LEVEL_PHONE, object : FinoCallBack<Map<String, Any>> {
                            //回调
                            override fun onSuccess(result: Map<String, Any>?) {
                                RetailAccountHelper.reloadLauncherActivity()
                            }

                            override fun onProgress(progress: Int, status: String) {
                                context?.startActivity<SplashActivity>()
                            }

                            override fun onError(code: Int, message: String) {
                                Log.d("LoginActivity", message)
                                //Toast.makeText(context, message, 				     Toast.LENGTH_LONG).show()
                                context?.let { loginGuest(it) }
                            }
                        })
// 交易账号登录
FinoChatClient.getInstance().accountManager().login(username, password, RetailAccountHelper.ACCOUNT_LEVEL_TRADE, object : FinoCallBack<Map<String, Any>> {
            //回调
            override fun onSuccess(result: Map<String, Any>) {

                val oldRoomId = intent?.getStringExtra("oldRoomId")
                if (oldRoomId != null) {
                RetailAccountHelper.startOrderRoomAutoOldRoomId = oldRoomId

                    RetailAccountHelper.isHomeActivityComplete = false

                    // 转移工单
                    if (RetailAccountHelper.isTranspose())
                        RetailAccountHelper.transposeOrderRetail(oldRoomId)
                }

                RetailAccountHelper.reloadLauncherActivity()
            }

            override fun onProgress(progress: Int, status: String) {
                startActivity(Intent(this@TradingAccountLoginAcitivity, SplashActivity::class.java))
            }

            override fun onError(code: Int, message: String) {
                //Toast.makeText(this@TradingAccountLoginAcitivity, message, Toast.LENGTH_LONG).show()
                loginGuest(this@TradingAccountLoginAcitivity)
            }
        })

员工端接入

build.gradle配置示例如下:

其中API为配置的服务器地址,AppType为“STAFF”表示为员工端。KEY是由凡泰签发给app的相关开关配置。

        cloudemp {
            dimension "default"
            applicationId getApplicationIdPrefix() + ".cloud.emp"
            resValue "string", "app_name", "金易联机构版"
            buildConfigField "String", "API", "\"https://mini.finogeeks.club\""
            buildConfigField "String", "KEY", "\"BepyGVtX0YmqNY8JSsAXUjvUhed672/BTvwl5Ojla6aemoUV4OdVTvzOfQ/LC5jqZK314hiGsPgrwi7+E8yVBkXpMQsxI8IFY9hpTu2VQsYifYjYmHqVkmQSqJ2yY49DRekxCzEjwgVj2GlO7ZVCxgdSgz6k3SArEiR3zjDYhMiQ\""
            buildConfigField "String", "AppType", "\"STAFF\""

            buildConfigField "String", "WECHAT_APPID", "\"wx3bfb3f78b4ade165\""
            buildConfigField "String", "ENV_VERSION", "\"release\""

            resValue "string", "app_scheme", "jfbempcloud"
            resValue "drawable", "app_icon", "@mipmap/ic_launcher"

            manifestPlaceholders = [amap_api_key: "48f1cf8d36e72f8bf036242bfd61ebc0",
                                    app_icon    : "@mipmap/ic_launcher"]
        }

页面组装

客户端页面包括,会话页面、工作页面、通讯录页面和我的页面,通过Fragment的形式以供组装。

FinoChatClient.getInstance().chatUIManager().conversationFragment(),
ARouter.getInstance().navigation(CustomerService.class).workFragment(),
FinoChatClient.getInstance().chatUIManager().contactFragment(),
ARouter.getInstance().navigation(CustomerService.class).employeeFragment()

第三方推送

ServiceFactory.getInstance().getThirdPartyPusher().push(this, "pushKey", null);

更多详情请参考demo工程demo 更多接口信息请参考api doc