663 lines
17 KiB
Plaintext
663 lines
17 KiB
Plaintext
|
|
# 实名认证功能及使用文档
|
|||
|
|
|
|||
|
|
## 一、功能概述
|
|||
|
|
|
|||
|
|
实名认证功能用于验证用户身份,确保用户信息的真实性和安全性。该功能包括:
|
|||
|
|
- 实名认证页面(输入姓名和身份证号)
|
|||
|
|
- 认证结果展示页面
|
|||
|
|
- 认证状态检查(在会话列表、更多操作等场景)
|
|||
|
|
- 认证状态存储(SharedPreferences + SDK UserInfo.extra字段)
|
|||
|
|
- 认证引导弹窗
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 二、相关文件
|
|||
|
|
|
|||
|
|
### 2.1 核心文件
|
|||
|
|
|
|||
|
|
#### Activity类
|
|||
|
|
- `app/src/main/java/com/xunpaisoft/social/im/setting/RealNameAuthActivity.java`
|
|||
|
|
- 实名认证输入页面,用户输入姓名和身份证号进行认证
|
|||
|
|
|
|||
|
|
- `app/src/main/java/com/xunpaisoft/social/im/setting/RealNameAuthResultActivity.java`
|
|||
|
|
- 实名认证结果展示页面,显示认证成功信息和脱敏后的姓名、身份证号
|
|||
|
|
|
|||
|
|
#### 工具类
|
|||
|
|
- `app/src/main/java/com/xunpaisoft/social/im/utils/UserInfoExtraHelper.java`
|
|||
|
|
- UserInfo扩展字段工具类,用于在SDK的UserInfo.extra字段中存储和读取realAuth
|
|||
|
|
|
|||
|
|
- `app/src/main/java/com/xunpaisoft/social/im/dialog/RealNameAuthDialog.java`
|
|||
|
|
- 实名认证引导弹窗工具类,可在应用任何地方调用显示引导弹窗
|
|||
|
|
|
|||
|
|
#### Fragment类
|
|||
|
|
- `app/src/main/java/com/xunpaisoft/social/im/main/MeFragment.java`
|
|||
|
|
- "我的"页面,包含实名认证入口,并在获取用户信息时同步认证状态到SDK
|
|||
|
|
|
|||
|
|
- `uikit/src/main/java/cn/wildfire/chat/kit/conversationlist/ConversationListFragment.java`
|
|||
|
|
- 会话列表页面,点击会话时检查实名认证状态
|
|||
|
|
|
|||
|
|
#### 数据模型
|
|||
|
|
- `uikit/src/main/java/cn/wildfire/chat/kit/net/model/RealNameAuthResult.java`
|
|||
|
|
- 实名认证接口返回结果数据模型
|
|||
|
|
|
|||
|
|
- `uikit/src/main/java/cn/wildfire/chat/kit/net/model/GetUserRealnameInfoResult.java`
|
|||
|
|
- 获取用户实名认证信息接口返回结果数据模型
|
|||
|
|
|
|||
|
|
- `uikit/src/main/java/cn/wildfire/chat/kit/net/model/GetUserInfoResult.java`
|
|||
|
|
- 获取用户信息接口返回结果数据模型(包含realauth字段)
|
|||
|
|
|
|||
|
|
#### SDK模型
|
|||
|
|
- `client/src/main/java/cn/wildfirechat/model/ModifyMyInfoType.java`
|
|||
|
|
- 用户信息修改类型枚举,包含Modify_Extra(8)用于扩展字段
|
|||
|
|
|
|||
|
|
- `client/src/main/java/cn/wildfirechat/model/ModifyMyInfoEntry.java`
|
|||
|
|
- 用户信息修改条目,用于通过SDK更新用户信息
|
|||
|
|
|
|||
|
|
### 2.2 布局文件
|
|||
|
|
- `app/src/main/res/layout/activity_real_name_auth.xml` - 实名认证输入页面布局
|
|||
|
|
- `app/src/main/res/layout/activity_real_name_auth_result.xml` - 认证结果页面布局
|
|||
|
|
- `app/src/main/res/layout/main_fragment_me.xml` - "我的"页面布局(包含实名认证入口)
|
|||
|
|
|
|||
|
|
### 2.3 网络接口
|
|||
|
|
- `uikit/src/main/java/cn/wildfire/chat/kit/net/AppService.java`
|
|||
|
|
- `realnameAuth()` - 提交实名认证
|
|||
|
|
- `getUserRealnameInfo()` - 获取用户实名认证信息
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 三、数据存储
|
|||
|
|
|
|||
|
|
### 3.1 SharedPreferences存储
|
|||
|
|
|
|||
|
|
**存储位置:** `social_app` SharedPreferences文件
|
|||
|
|
**Key:** `realAuth`(定义在 `Constants.REAL_AUTH`)
|
|||
|
|
**值:**
|
|||
|
|
- `"1"` - 已认证成功
|
|||
|
|
- `"0"` - 未认证(默认值)
|
|||
|
|
|
|||
|
|
**使用工具类:** `SharedPreferencesUtils`
|
|||
|
|
```java
|
|||
|
|
// 保存
|
|||
|
|
SharedPreferencesUtils.putString(Constants.REAL_AUTH, "1");
|
|||
|
|
|
|||
|
|
// 读取
|
|||
|
|
String realAuth = SharedPreferencesUtils.getString(Constants.REAL_AUTH, "0");
|
|||
|
|
boolean isAuth = "1".equals(realAuth);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3.2 SDK UserInfo.extra字段存储
|
|||
|
|
|
|||
|
|
**存储位置:** 野火SDK的 `UserInfo.extra` 字段
|
|||
|
|
**数据格式:** JSON字符串
|
|||
|
|
**示例:**
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"realAuth": "1"
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**使用工具类:** `UserInfoExtraHelper`
|
|||
|
|
```java
|
|||
|
|
// 更新到SDK
|
|||
|
|
UserInfoExtraHelper.setRealAuthToSDK(callback);
|
|||
|
|
|
|||
|
|
// 从UserInfo读取
|
|||
|
|
UserInfo userInfo = ChatManager.Instance().getUserInfo(userId, false);
|
|||
|
|
boolean isAuth = UserInfoExtraHelper.isRealAuth(userInfo);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3.3 存储时机
|
|||
|
|
|
|||
|
|
1. **认证成功时:**
|
|||
|
|
- 保存到 SharedPreferences
|
|||
|
|
- 更新到 SDK UserInfo.extra字段
|
|||
|
|
|
|||
|
|
2. **获取用户信息时:**
|
|||
|
|
- 从服务器获取的realauth保存到 SharedPreferences
|
|||
|
|
- 如果已认证但SDK中未同步,自动同步到SDK
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 四、API接口
|
|||
|
|
|
|||
|
|
### 4.1 提交实名认证
|
|||
|
|
|
|||
|
|
**接口:** `POST /api/user/realnameAuth`
|
|||
|
|
|
|||
|
|
**请求参数:**
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"username": "张三",
|
|||
|
|
"idcard": "110101199001011234"
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**响应示例:**
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"error_code": 0,
|
|||
|
|
"reason": "",
|
|||
|
|
"result": {
|
|||
|
|
"realname": "张*",
|
|||
|
|
"idcard": "110101********1234",
|
|||
|
|
"isok": 1,
|
|||
|
|
"IdCardInfor": {
|
|||
|
|
"name": "张三",
|
|||
|
|
"idcard": "110101199001011234"
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
"sn": "xxx"
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**调用方式:**
|
|||
|
|
```java
|
|||
|
|
AppService.Instance().realnameAuth(name, idNumber, new SimpleCallback<RealNameAuthResult>() {
|
|||
|
|
@Override
|
|||
|
|
public void onUiSuccess(RealNameAuthResult result) {
|
|||
|
|
if (result != null && result.isSuccess()) {
|
|||
|
|
// 认证成功处理
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@Override
|
|||
|
|
public void onUiFailure(int code, String msg) {
|
|||
|
|
// 认证失败处理
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4.2 获取用户实名认证信息
|
|||
|
|
|
|||
|
|
**接口:** `POST /api/user/getUserRealnameInfo`
|
|||
|
|
|
|||
|
|
**响应示例:**
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"id": 123,
|
|||
|
|
"user_id": "1845",
|
|||
|
|
"name": "张*",
|
|||
|
|
"idcard": "110101********1234",
|
|||
|
|
"phone": "",
|
|||
|
|
"address": "",
|
|||
|
|
"birthday": "",
|
|||
|
|
"sex": "",
|
|||
|
|
"status": 1,
|
|||
|
|
"createtime": "2025-01-01 10:00:00",
|
|||
|
|
"updatetime": "2025-01-01 10:00:00",
|
|||
|
|
"status_text": "已认证"
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**调用方式:**
|
|||
|
|
```java
|
|||
|
|
AppService.Instance().getUserRealnameInfo(new SimpleCallback<GetUserRealnameInfoResult>() {
|
|||
|
|
@Override
|
|||
|
|
public void onUiSuccess(GetUserRealnameInfoResult result) {
|
|||
|
|
if (result != null && result.isSuccess()) {
|
|||
|
|
GetUserRealnameInfoResult data = result.getData();
|
|||
|
|
String name = data.getName();
|
|||
|
|
String idcard = data.getIdcard();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4.3 获取用户信息(包含realauth字段)
|
|||
|
|
|
|||
|
|
**接口:** `POST /api/user/getUserInfo`
|
|||
|
|
|
|||
|
|
**响应中的realauth字段:**
|
|||
|
|
- `"1"` - 已认证成功
|
|||
|
|
- `"0"` - 未认证
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 五、功能使用
|
|||
|
|
|
|||
|
|
### 5.1 实名认证入口
|
|||
|
|
|
|||
|
|
**位置:** "我的"页面(MeFragment)
|
|||
|
|
|
|||
|
|
**布局:** `main_fragment_me.xml`
|
|||
|
|
```xml
|
|||
|
|
<cn.wildfire.chat.kit.widget.OptionItemView
|
|||
|
|
android:id="@+id/realNameAuthOptionItemView"
|
|||
|
|
style="@style/OptionItem"
|
|||
|
|
app:show_divider="true"
|
|||
|
|
app:start_src="@mipmap/icon_my_shezhi"
|
|||
|
|
app:title="实名认证" />
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**点击逻辑:** `MeFragment.realNameAuth()`
|
|||
|
|
- 如果已认证:跳转到 `RealNameAuthResultActivity`(认证结果页面)
|
|||
|
|
- 如果未认证:跳转到 `RealNameAuthActivity`(认证输入页面)
|
|||
|
|
|
|||
|
|
### 5.2 实名认证流程
|
|||
|
|
|
|||
|
|
1. **用户点击"实名认证"入口**
|
|||
|
|
- 检查认证状态(`Constants.isRealAuth()`)
|
|||
|
|
- 根据状态跳转到相应页面
|
|||
|
|
|
|||
|
|
2. **输入认证信息(RealNameAuthActivity)**
|
|||
|
|
- 输入真实姓名
|
|||
|
|
- 选择证件类型(默认:居民身份证)
|
|||
|
|
- 输入证件号码
|
|||
|
|
- 点击"提交"按钮
|
|||
|
|
|
|||
|
|
3. **提交认证(submitToServer)**
|
|||
|
|
- 调用 `AppService.realnameAuth()` 接口
|
|||
|
|
- 认证成功:
|
|||
|
|
- 保存到 SharedPreferences(`Constants.REAL_AUTH = "1"`)
|
|||
|
|
- 更新到 SDK UserInfo.extra字段(`UserInfoExtraHelper.setRealAuthToSDK()`)
|
|||
|
|
- 跳转到认证结果页面
|
|||
|
|
|
|||
|
|
4. **显示认证结果(RealNameAuthResultActivity)**
|
|||
|
|
- 如果Intent中有数据,直接显示
|
|||
|
|
- 如果没有,调用 `AppService.getUserRealnameInfo()` 从服务器获取
|
|||
|
|
- 显示脱敏后的姓名和身份证号
|
|||
|
|
|
|||
|
|
### 5.3 认证状态检查
|
|||
|
|
|
|||
|
|
#### 5.3.1 在会话列表中检查
|
|||
|
|
|
|||
|
|
**位置:** `ConversationListFragment.handleConversationClick()`
|
|||
|
|
|
|||
|
|
**检查逻辑:**
|
|||
|
|
1. 优先从 `UserInfo.extra` 字段读取
|
|||
|
|
2. 如果extra中没有,从 SharedPreferences 读取
|
|||
|
|
3. 如果未认证,显示引导弹窗
|
|||
|
|
4. 如果已认证,正常跳转到会话页面
|
|||
|
|
|
|||
|
|
**代码示例:**
|
|||
|
|
```java
|
|||
|
|
private void handleConversationClick(ConversationInfo conversationInfo) {
|
|||
|
|
String userId = ChatManager.Instance().getUserId();
|
|||
|
|
boolean isRealAuth = false;
|
|||
|
|
|
|||
|
|
// 1. 从UserInfo.extra读取
|
|||
|
|
if (userId != null) {
|
|||
|
|
UserInfo currentUserInfo = ChatManager.Instance().getUserInfo(userId, false);
|
|||
|
|
if (currentUserInfo != null && currentUserInfo.extra != null) {
|
|||
|
|
String realAuth = getRealAuthFromExtra(currentUserInfo.extra);
|
|||
|
|
isRealAuth = "1".equals(realAuth);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 2. 从SharedPreferences读取(兼容)
|
|||
|
|
if (!isRealAuth) {
|
|||
|
|
String realAuth = SharedPreferencesUtils.getString(Constants.REAL_AUTH, "0");
|
|||
|
|
isRealAuth = "1".equals(realAuth);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 3. 根据结果处理
|
|||
|
|
if (!isRealAuth) {
|
|||
|
|
showRealNameAuthDialog(); // 显示引导弹窗
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 已认证,正常跳转
|
|||
|
|
Intent intent = new Intent(getActivity(), ConversationActivity.class);
|
|||
|
|
intent.putExtra("conversation", conversationInfo.conversation);
|
|||
|
|
startActivity(intent);
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 5.3.2 在更多操作中检查
|
|||
|
|
|
|||
|
|
**位置:** `MainActivity.showMoreActionMenu()`
|
|||
|
|
|
|||
|
|
**检查逻辑:**
|
|||
|
|
```java
|
|||
|
|
private void showMoreActionMenu() {
|
|||
|
|
// 检查是否已实名认证
|
|||
|
|
if (!Constants.isRealAuth()) {
|
|||
|
|
RealNameAuthDialog.show(this);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 已认证,显示更多操作菜单
|
|||
|
|
// ...
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 5.4 认证引导弹窗
|
|||
|
|
|
|||
|
|
**工具类:** `RealNameAuthDialog`
|
|||
|
|
|
|||
|
|
**使用方式:**
|
|||
|
|
|
|||
|
|
1. **简单调用(默认行为)**
|
|||
|
|
```java
|
|||
|
|
// 在任何Activity中调用
|
|||
|
|
RealNameAuthDialog.show(this);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
2. **带回调的调用(自定义行为)**
|
|||
|
|
```java
|
|||
|
|
RealNameAuthDialog.show(this, new RealNameAuthDialog.OnRealNameAuthDialogListener() {
|
|||
|
|
@Override
|
|||
|
|
public void onConfirm() {
|
|||
|
|
// 自定义确认行为
|
|||
|
|
Intent intent = new Intent(this, RealNameAuthActivity.class);
|
|||
|
|
startActivity(intent);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@Override
|
|||
|
|
public void onCancel() {
|
|||
|
|
// 自定义取消行为
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**弹窗内容:**
|
|||
|
|
- 标题:"温馨提示"
|
|||
|
|
- 内容:"为保障用户信息和安全,需要进行实名认证后才能开启相关服务"
|
|||
|
|
- 按钮:
|
|||
|
|
- "取消"(关闭弹窗)
|
|||
|
|
- "去认证"(跳转到实名认证页面)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 六、工具类使用
|
|||
|
|
|
|||
|
|
### 6.1 UserInfoExtraHelper
|
|||
|
|
|
|||
|
|
#### 6.1.1 读取认证状态
|
|||
|
|
|
|||
|
|
```java
|
|||
|
|
// 从UserInfo读取
|
|||
|
|
UserInfo userInfo = ChatManager.Instance().getUserInfo(userId, false);
|
|||
|
|
String realAuth = UserInfoExtraHelper.getRealAuth(userInfo);
|
|||
|
|
boolean isAuth = UserInfoExtraHelper.isRealAuth(userInfo);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 6.1.2 更新认证状态到SDK
|
|||
|
|
|
|||
|
|
```java
|
|||
|
|
// 设置为已认证
|
|||
|
|
UserInfoExtraHelper.setRealAuthToSDK(new GeneralCallback() {
|
|||
|
|
@Override
|
|||
|
|
public void onSuccess() {
|
|||
|
|
Log.d("Tag", "更新成功");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@Override
|
|||
|
|
public void onFail(int errorCode) {
|
|||
|
|
Log.e("Tag", "更新失败: " + errorCode);
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 设置为未认证
|
|||
|
|
UserInfoExtraHelper.clearRealAuthFromSDK(callback);
|
|||
|
|
|
|||
|
|
// 自定义值
|
|||
|
|
UserInfoExtraHelper.updateRealAuthToSDK("1", callback);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 6.1.3 构建extra JSON字符串
|
|||
|
|
|
|||
|
|
```java
|
|||
|
|
String currentExtra = userInfo.extra; // 可能为null
|
|||
|
|
String newExtra = UserInfoExtraHelper.buildExtraWithRealAuth(currentExtra, "1");
|
|||
|
|
// 结果: {"realAuth":"1"}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 6.2 Constants工具方法
|
|||
|
|
|
|||
|
|
```java
|
|||
|
|
// 获取认证状态字符串
|
|||
|
|
String realAuth = Constants.getRealAuth(); // 返回 "1" 或 "0"
|
|||
|
|
|
|||
|
|
// 判断是否已认证
|
|||
|
|
boolean isAuth = Constants.isRealAuth(); // 返回 true 或 false
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 七、SDK扩展字段使用
|
|||
|
|
|
|||
|
|
### 7.1 Modify_Extra字段说明
|
|||
|
|
|
|||
|
|
`ModifyMyInfoType.Modify_Extra` 是野火SDK提供的扩展字段类型,用于在 `UserInfo.extra` 字段中存储自定义JSON数据。
|
|||
|
|
|
|||
|
|
**使用步骤:**
|
|||
|
|
|
|||
|
|
1. **构建JSON字符串**
|
|||
|
|
```java
|
|||
|
|
JSONObject jsonObject = new JSONObject();
|
|||
|
|
jsonObject.put("realAuth", "1");
|
|||
|
|
String extraJson = jsonObject.toString();
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
2. **创建ModifyMyInfoEntry**
|
|||
|
|
```java
|
|||
|
|
ModifyMyInfoEntry entry = new ModifyMyInfoEntry(
|
|||
|
|
ModifyMyInfoType.Modify_Extra,
|
|||
|
|
extraJson
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
3. **调用SDK更新**
|
|||
|
|
```java
|
|||
|
|
List<ModifyMyInfoEntry> entries = new ArrayList<>();
|
|||
|
|
entries.add(entry);
|
|||
|
|
ChatManager.Instance().modifyMyInfo(entries, callback);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 7.2 读取extra字段
|
|||
|
|
|
|||
|
|
```java
|
|||
|
|
UserInfo userInfo = ChatManager.Instance().getUserInfo(userId, false);
|
|||
|
|
if (userInfo != null && userInfo.extra != null) {
|
|||
|
|
try {
|
|||
|
|
JSONObject jsonObject = new JSONObject(userInfo.extra);
|
|||
|
|
String realAuth = jsonObject.optString("realAuth", "0");
|
|||
|
|
} catch (JSONException e) {
|
|||
|
|
e.printStackTrace();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 八、同步机制
|
|||
|
|
|
|||
|
|
### 8.1 认证成功时同步
|
|||
|
|
|
|||
|
|
**位置:** `RealNameAuthActivity.submitToServer()`
|
|||
|
|
|
|||
|
|
认证成功后:
|
|||
|
|
1. 保存到 SharedPreferences
|
|||
|
|
2. 调用 `UserInfoExtraHelper.setRealAuthToSDK()` 更新到SDK
|
|||
|
|
|
|||
|
|
### 8.2 获取用户信息时同步
|
|||
|
|
|
|||
|
|
**位置:** `MeFragment.getOtherUserInfo()`
|
|||
|
|
|
|||
|
|
当从服务器获取到 `realauth = "1"` 时:
|
|||
|
|
1. 保存到 SharedPreferences
|
|||
|
|
2. 检查SDK的 `UserInfo.extra` 字段
|
|||
|
|
3. 如果extra中没有 `realAuth` 或值不是 "1",自动同步更新
|
|||
|
|
|
|||
|
|
**同步逻辑:**
|
|||
|
|
```java
|
|||
|
|
if ("1".equals(data.getRealauth())) {
|
|||
|
|
// 检查SDK中是否已有realAuth
|
|||
|
|
UserInfo currentUserInfo = ChatManager.Instance().getUserInfo(userId, false);
|
|||
|
|
String currentExtra = currentUserInfo != null ? currentUserInfo.extra : null;
|
|||
|
|
|
|||
|
|
boolean needSync = true;
|
|||
|
|
if (currentExtra != null && !currentExtra.isEmpty()) {
|
|||
|
|
JSONObject jsonObject = new JSONObject(currentExtra);
|
|||
|
|
String existingRealAuth = jsonObject.optString("realAuth", "0");
|
|||
|
|
if ("1".equals(existingRealAuth)) {
|
|||
|
|
needSync = false; // 已经同步过了
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (needSync) {
|
|||
|
|
UserInfoExtraHelper.setRealAuthToSDK(callback);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 九、调试日志
|
|||
|
|
|
|||
|
|
### 9.1 日志标签
|
|||
|
|
|
|||
|
|
- `ConversationListFragment` - 会话列表认证检查日志
|
|||
|
|
- `UserInfoExtraHelper` - SDK更新日志
|
|||
|
|
- `MeFragment` - 同步检测日志
|
|||
|
|
- `RealNameAuth` - 认证流程日志
|
|||
|
|
|
|||
|
|
### 9.2 关键日志点
|
|||
|
|
|
|||
|
|
1. **认证状态检查**
|
|||
|
|
```
|
|||
|
|
D/ConversationListFragment: === 开始检查实名认证状态 ===
|
|||
|
|
D/ConversationListFragment: 当前用户ID: 1845
|
|||
|
|
D/ConversationListFragment: UserInfo.extra 值: {"realAuth":"1"}
|
|||
|
|
D/ConversationListFragment: 从UserInfo.extra解析的realAuth: 1
|
|||
|
|
D/ConversationListFragment: ✓ 从UserInfo.extra读取到已认证状态
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
2. **SDK更新**
|
|||
|
|
```
|
|||
|
|
D/UserInfoExtraHelper: === 开始更新realAuth到SDK ===
|
|||
|
|
D/UserInfoExtraHelper: 要设置的realAuth值: 1
|
|||
|
|
D/UserInfoExtraHelper: 当前UserInfo.extra: null
|
|||
|
|
D/UserInfoExtraHelper: 构建后的newExtra: {"realAuth":"1"}
|
|||
|
|
D/UserInfoExtraHelper: ✓ 成功更新realAuth到SDK的UserInfo.extra
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
3. **同步检测**
|
|||
|
|
```
|
|||
|
|
D/MeFragment: 检测到已认证但SDK中extra字段未同步,开始同步...
|
|||
|
|
D/MeFragment: ✓ 成功同步realAuth到SDK的UserInfo.extra
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 十、注意事项
|
|||
|
|
|
|||
|
|
### 10.1 数据一致性
|
|||
|
|
|
|||
|
|
- SharedPreferences 和 SDK UserInfo.extra 字段都存储认证状态
|
|||
|
|
- 优先从 SDK 的 extra 字段读取(更可靠)
|
|||
|
|
- SharedPreferences 作为兼容和备用方案
|
|||
|
|
|
|||
|
|
### 10.2 更新extra字段时
|
|||
|
|
|
|||
|
|
- 必须保留现有数据,只更新 `realAuth` 字段
|
|||
|
|
- 使用 `UserInfoExtraHelper.buildExtraWithRealAuth()` 方法确保数据不丢失
|
|||
|
|
|
|||
|
|
### 10.3 错误处理
|
|||
|
|
|
|||
|
|
- SDK更新失败不影响 SharedPreferences 的保存
|
|||
|
|
- 即使SDK更新失败,认证状态仍可通过 SharedPreferences 读取
|
|||
|
|
|
|||
|
|
### 10.4 性能考虑
|
|||
|
|
|
|||
|
|
- 同步操作是异步的,不会阻塞UI
|
|||
|
|
- 在获取用户信息时进行同步,避免频繁调用
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 十一、常见问题
|
|||
|
|
|
|||
|
|
### Q1: UserInfo.extra为空怎么办?
|
|||
|
|
|
|||
|
|
**A:**
|
|||
|
|
1. 检查是否调用了 `UserInfoExtraHelper.setRealAuthToSDK()`
|
|||
|
|
2. 检查SDK更新是否成功(查看日志)
|
|||
|
|
3. 如果之前已认证,登录时会自动同步
|
|||
|
|
|
|||
|
|
### Q2: 如何手动同步认证状态到SDK?
|
|||
|
|
|
|||
|
|
**A:**
|
|||
|
|
```java
|
|||
|
|
// 如果SharedPreferences中有认证状态,但SDK中没有
|
|||
|
|
if (Constants.isRealAuth()) {
|
|||
|
|
UserInfoExtraHelper.setRealAuthToSDK(new GeneralCallback() {
|
|||
|
|
@Override
|
|||
|
|
public void onSuccess() {
|
|||
|
|
// 同步成功
|
|||
|
|
}
|
|||
|
|
@Override
|
|||
|
|
public void onFail(int errorCode) {
|
|||
|
|
// 同步失败
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Q3: 如何判断用户是否已认证?
|
|||
|
|
|
|||
|
|
**A:**
|
|||
|
|
```java
|
|||
|
|
// 方式1:使用Constants工具方法(推荐)
|
|||
|
|
boolean isAuth = Constants.isRealAuth();
|
|||
|
|
|
|||
|
|
// 方式2:从UserInfo.extra读取
|
|||
|
|
UserInfo userInfo = ChatManager.Instance().getUserInfo(userId, false);
|
|||
|
|
boolean isAuth = UserInfoExtraHelper.isRealAuth(userInfo);
|
|||
|
|
|
|||
|
|
// 方式3:从SharedPreferences读取
|
|||
|
|
String realAuth = SharedPreferencesUtils.getString(Constants.REAL_AUTH, "0");
|
|||
|
|
boolean isAuth = "1".equals(realAuth);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Q4: 认证状态在哪里检查?
|
|||
|
|
|
|||
|
|
**A:**
|
|||
|
|
- 会话列表点击时:`ConversationListFragment.handleConversationClick()`
|
|||
|
|
- 更多操作点击时:`MainActivity.showMoreActionMenu()`
|
|||
|
|
- 实名认证入口点击时:`MeFragment.realNameAuth()`
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 十二、版本历史
|
|||
|
|
|
|||
|
|
- **v1.0** - 初始版本
|
|||
|
|
- 实现基本的实名认证功能
|
|||
|
|
- 支持SharedPreferences存储
|
|||
|
|
- 支持SDK UserInfo.extra字段存储
|
|||
|
|
- 实现认证状态检查和引导弹窗
|
|||
|
|
- 实现自动同步机制
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 十三、相关常量
|
|||
|
|
|
|||
|
|
**定义位置:** `uikit/src/main/java/cn/wildfire/chat/kit/net/Constants.java`
|
|||
|
|
|
|||
|
|
```java
|
|||
|
|
public static final String REAL_AUTH = "realAuth";
|
|||
|
|
|
|||
|
|
public static String getRealAuth() {
|
|||
|
|
return SharedPreferencesUtils.getString(REAL_AUTH, "0");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static boolean isRealAuth() {
|
|||
|
|
return "1".equals(getRealAuth());
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 十四、总结
|
|||
|
|
|
|||
|
|
实名认证功能通过以下方式实现:
|
|||
|
|
|
|||
|
|
1. **数据存储:** SharedPreferences + SDK UserInfo.extra字段(双重存储)
|
|||
|
|
2. **状态检查:** 优先从SDK读取,兼容SharedPreferences
|
|||
|
|
3. **自动同步:** 获取用户信息时自动同步到SDK
|
|||
|
|
4. **引导机制:** 未认证时显示引导弹窗
|
|||
|
|
5. **工具类封装:** 提供便捷的读写方法
|
|||
|
|
|
|||
|
|
该设计确保了数据的一致性和可靠性,同时提供了良好的用户体验。
|
|||
|
|
|