FinClip为企业提供小程序生态圈技术产品,开发者可在FinClip小程序开发帮助中心找到相关FinClip小程序指引

# 小程序登录常见问题

请注意

针对微信登录,您也可以使用 FinClip 提供的关联微信小程序登录功能,降低开发成本,快速复用微信登录能力。点击这里了解能力

在微信小程序下,小程序登录功能一般会通过 OpenIDUnionID 作为唯一标识,与小程序服务的账号体系进行关联打通,完成用户账户体系的构建与设计。

对于从微信小程序环境迁移到 FinClip 下的小程序,就会遇到如下问题:

  1. 登录流程如何快速复用?怎样与小程序服务的账号体系关联?
  2. 如何让微信小程序中的用户数据与 FinClip 的数据打通?双方的账号体系如何关联?

遇到上述问题时,您可通过以下方案尝试解决:

# 1. 登录方案

# 方案一:服务端改造

适用场景:平台方通过 FinClip 构建自有生态,FinClip 环境中运行的都是第三方的小程序(即平台方无法修改小程序代码)。

  • 第一步:在 App 中通过自定义 API 注入 wx.login 方法,按照微信小程序的格式返回 code;
  • 第二步:小程序无需改动,按照在微信端的实现,此时会将 code 发送给开发者的服务器;
  • 第三步:开发者服务器进行适配,通过 code 可判断登录来自 FinClip 平台,从 code 中解析出 UserID,返回自身账户体系的内容即可。

# 方案二:服务端改造(唤起微信授权)

使用场景:平台方通过 FinClip 完成自身功能的拆分,小程序都由平台方自己开发(即平台方可以修改小程序代码)。

  • 第一步:SDK 中集成微信开发平台 SDK;
  • 第二步:使用自定义 API 注入 wx.login,唤起微信授权后即可取得返回 code,此时可能需要对 code 拼接唯一标识;
  • 第三步:小程序无需改动,按照在微信端的实现,此时会将 code 发送给开发者的服务器;
  • 第四步:服务端根据 code 唯一标识,调用不同的授权接口取得 OpenID,查询登录态返回;

限制:由于微信限制不同主体,不同开放平台下的 OpenID 是不一致的,此时小程序需要关联到同一主体,或者同一开放平台(此时唯一标识为 UnionID)。

# 方案三:小程序改造

适用场景:对小程序进行逻辑修改,当判断 FinClip 环境中时,直接从 wx.login 或者自定义 API( 如 wx.loginFinlip) 中获取需要的信息(即平台方可以修改小程序代码)。

  • APP 使用自定义 API 注入wx.login,返回当前 APP 用户的登录态即可。

# 2. 自定义接口实现代码

基于方案三,我们提供了对应的实现代码,供您参考。

# 2.1 APP接入微信登录

若您需要实现APP的微信账号授权登录,请参考微信开放平台的移动应用开发 (opens new window)和文档微信授权登录开发文档 (opens new window)进行实现,若不需要则直接从第2步开始即可。

# 2.2 APP实现自定义注入接口

首先,APP需要参考iOS SDK自定义注入接口安卓 SDK自定义注入接口两份文档,将账号的授权登录能力注入至SDK中,让小程序能调用,详细说明如下。

Android端: 为了让小程序能够获取到小程序以外的APP数据,需要注册小程序自定义接口,自定义小程序接口具体说明请参照FinClip小程序开放平台-自定义小程序接口FinClip小程序开放平台-在小程序进程中注册api

  1. 自定义login接口
  2. 自定义Api类,指定api名称为“login”;
public class LoginApi extends AbsApi {

    private final static String API_NAME_LOGIN = "login"; // 小程序基础库调用的api名称

    @Override
    public String[] apis() {
        return new String[]{API_NAME_LOGIN};
    }
}
  1. 注册自定义Api;

示例展示了用户授权提示Dialog,需要Activity对象作为Dialog的context参数, 所以需要在小程进程注册自定义Api。

  if (FinAppClient.INSTANCE.isFinAppProcess(this)) {
      // 小程序进程
      // 小程序进程中注册api的方法能获取到小程序所在activity对象,可以用做创建对话框的context参数)
      FinAppProcessClient.INSTANCE.setCallback(new FinAppProcessClient.Callback() {
          @Override
          public List<IApi> getRegisterExtensionApis(@NotNull Activity activity) {
              ArrayList<IApi> apis = new ArrayList<>();
              apis.add(new LoginApi());
              return apis;
          }

          @Nullable
          @Override
          public List<IApi> getRegisterExtensionWebApis(@NotNull Activity activity) {
              return null;
          }
      });
      return;
  }
  1. 实现自定义Api invoke()方法;

先展示授权提示Dialog(开发者请根据需求决定是否展示授权提示Dialog), 然后再从主进程(App进程)获取用户登录信息。

public class LoginApi extends AbsApi {

    @Override
    public void invoke(String event, JSONObject param, ICallback callback) {
        if (event.equals(API_NAME_LOGIN)) {
            showAuthDialog(callback);
        }
    }

    /**
     * 显示获取用户登录信息的授权提示对话框
     */
    private void showAuthDialog(final ICallback callback) {
        // 是否需要显示授权提示对话框请开发者按照产品需求自行处理
        new AlertDialog.Builder(activity)
                .setTitle("是否同意授权获取用户登录信息?")
                .setNegativeButton("拒绝", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        callback.onFail();
                    }
                })
                .setPositiveButton("同意", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        loginMainProcess(callback);
                    }
                })
                .show();
    }

    /**
     * 从主进程获取用户登录信息
     */
    private void loginMainProcess(final ICallback callback) {
        // 小程序进程调用主进程,在主进程获取用户信息后返回给小程序进程
        FinAppProcessClient.INSTANCE.getAppletProcessApiManager()
                .callInMainProcess(API_NAME_LOGIN, null, new FinCallback<String>() {
                    @Override
                    public void onSuccess(final String result) {
                        // 需要在主线程调用callback方法
                        activity.runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                try {
                                    callback.onSuccess(new JSONObject(result));
                                } catch (JSONException e) {
                                    e.printStackTrace();
                                    callback.onFail();
                                }
                            }
                        });
                    }

                    @Override
                    public void onError(int code, String error) {
                        callback.onFail();
                    }

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

}

随后在主进程(通常是在Application里面,开发者也可以选择其他合适的位置), 返回用户登录信息给小程序进程。

// 在主进程设置"小程序进程调用主进程"的处理方法
// 开发者也可以选择在主进程其他合适的代码位置设置处理方法
FinAppClient.INSTANCE.getAppletApiManager()
    .setAppletProcessCallHandler(new IAppletApiManager.AppletProcessCallHandler() {
        @Override
        public void onAppletProcessCall(@NotNull String name,
                                        @Nullable String params,
                                        @Nullable FinCallback<String> callback) {
            if (callback != null) {
                if (name.equals(LoginApi.API_NAME_LOGIN)) {
                    // 从主进程获取登录信息,返回给小程序进程
                    // 这里返回的是虚拟的用户登录信息,开发者请从APP里面自行获取用户登录信息
                    JSONObject jsonObject = new JSONObject();
                    try {
                        jsonObject.put("userId", "123");
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                    callback.onSuccess(jsonObject.toString());
                }
            }
        }
    });

至此,小程序通过自定义Api从APP获取用户登录信息的整个流程就已经完成了。

注意:如果产品需求不需要展示用户授权提示Dialog,建议在主进程(APP进程)注册自定义Api,从而省掉上述在小程序进程调用主进程(APP进程)方法获取数据的过程。

  1. 自定义getUserProfile接口

    1. 自定义接口名称为“getUserProfile”的API。
    2. 自定义getUserProfile接口流程与自定义login接口流程一致,此处不再赘述。
  2. FinClip还提供了官方的安卓APP Demo 工程和小程序 (opens new window)作为示范,如有需求,您可以前往下载体验。

iOS 端:

  1. 在原生App中调用sdk的注入api方法,getUserProfile是微信小程序对应的获取用户信息方法名。
[[FATClient sharedClient]registerExtensionApi:@"getUserProfile" handle:^(id param, FATExtensionApiCallback callback) {
        //返回用户信息,未登录,可以在这里弹出登录,登录完成后返回用户信息
        NSDictionary *userInfo = @{@"nickName":@"张三",@"avatarUrl":@"",@"gender":@1,@"country":@"中国",@"province":@"广东省",@"city":@"深圳",@"language":@"zh_CN"};
        NSDictionary *resDic = @{@"userInfo":userInfo};
        //回调给小程序用户信息的结果
        if (resDic) {
            callback(FATExtensionCodeSuccess,resDic);
        }else{
            callback(FATExtensionCodeFailure,resDic);
        }
    }];
  1. 小程序中调用声明的getUserProfile,得到用户信息
wx.getUserProfile({
      success: (res) => {
        this.setData({
          userInfo: res.userInfo,
          hasUserInfo: true
        })
      }
    })
  1. FinClip还提供了官方的iOS APP Demo 工程和小程序 (opens new window)作为示范,如有需求,您可以前往下载体验。

# 2.3 小程序实现接口的调用

小程序如需支持 login 和 getUserProfile api,需要在 APP  以注入 API 的方式实现,注入 API 的实现步骤可参阅第2步。

需要注意的是,login 和 getUserProfile 为小程序默认注入接口,无需在小程序根目录配置 FinChatConf 即可调通该两个接口。

APP 未注入相关接口时,调用会报错并执行 fail 回调。

  1. 调起登录接口
wx.login({
  param1: '', // 按需添加参数,会透传给 APP 处理
  success: (res) => {
    console.log(res)
  },
  fail: (res) => {
    console.log(res.errMsg)
  }
})
  1. 调起获取用户信息接口
wx.getUserProfile({
  success: (res) => {
    console.log('getUserProfile success', res)
  },
  fail: (res) => {
    console.log('getUserProfile fail', res.errMsg)
  }
})

# 3. 常见问题

微信官方公告 (opens new window),自 2021 年 12 月 27 日后不再向开发者输出用户昵称与头像信息,您可能需要自行处理获取用户头像与昵称的相关逻辑。

常见的处理逻辑如下:

  1. 在小程序或小游戏中,不显示用户的头像与昵称,使用其他字段内容代替;
  2. 在用户进入小程序或小游戏后,随机给用户生成头像与昵称;
  3. 在用户进入小程序或小游戏后,引导用户自行配置头像,昵称等内容信息。
© FinClip with ❤ , Since 2017