g_emoji_package.totalSize = 0;
}
+/* 读取整个文件为字符串(成功返回0,失败返回-1;调用者负责free(*out_str))*/
+static int ln_read_file_to_string(const char *file_path, char **out_str)
+{
+ if (out_str)
+ *out_str = NULL;
+ if (!file_path || !out_str)
+ return -1;
+ FILE *fp = fopen(file_path, "rb");
+ if (!fp)
+ return -1;
+ if (fseek(fp, 0, SEEK_END) != 0)
+ {
+ fclose(fp);
+ return -1;
+ }
+ long len = ftell(fp);
+ if (len < 0 || len > (1024 * 1024))
+ {
+ fclose(fp);
+ return -1;
+ }
+ if (fseek(fp, 0, SEEK_SET) != 0)
+ {
+ fclose(fp);
+ return -1;
+ }
+ char *buf = (char *)malloc((size_t)len + 1);
+ if (!buf)
+ {
+ fclose(fp);
+ return -1;
+ }
+ size_t n = fread(buf, 1, (size_t)len, fp);
+ fclose(fp);
+ buf[n] = '\0';
+ *out_str = buf;
+ return 0;
+}
+
+/* 将字符串写入文件(成功返回0,失败返回-1)*/
+static int ln_write_string_to_file(const char *file_path, const char *str)
+{
+ if (!file_path || !str)
+ return -1;
+ /* 确保目录存在 */
+ uapi_create_folder((char *)LN_DATA_PATH);
+ uapi_create_folder((char *)(LN_DATA_PATH "/emoji"));
+ FILE *fp = fopen(file_path, "wb");
+ if (!fp)
+ return -1;
+ size_t len = strlen(str);
+ size_t n = fwrite(str, 1, len, fp);
+ fclose(fp);
+ return (n == len) ? 0 : -1;
+}
+
+/* 加载表情组根对象(包含emojiGroups数组);不存在则创建默认结构 */
+static cJSON *ln_load_emoji_groups_root(void)
+{
+ char *content = NULL;
+ if (ln_read_file_to_string(LN_EMOJI_GROUPS_FILE, &content) == 0 && content)
+ {
+ cJSON *root = cJSON_Parse(content);
+ free(content);
+ if (root)
+ return root;
+ }
+ /* 文件不存在或解析失败,创建默认 */
+ cJSON *root = cJSON_CreateObject();
+ if (!root)
+ return NULL;
+ cJSON *arr = cJSON_CreateArray();
+ if (!arr)
+ {
+ cJSON_Delete(root);
+ return NULL;
+ }
+ cJSON_AddItemToObject(root, "emojiGroups", arr);
+ return root;
+}
+
+/* 保存根对象到磁盘 */
+static int ln_save_emoji_groups_root(cJSON *root)
+{
+ if (!root)
+ return -1;
+ char *json = cJSON_PrintUnformatted(root);
+ if (!json)
+ return -1;
+ int ret = ln_write_string_to_file(LN_EMOJI_GROUPS_FILE, json);
+ cJSON_free(json);
+ return ret;
+}
+
+/* 获取或创建数组 */
+static cJSON *ln_get_or_create_groups_array(cJSON *root)
+{
+ if (!root)
+ return NULL;
+ cJSON *arr = cJSON_GetObjectItem(root, "emojiGroups");
+ if (!arr || !cJSON_IsArray(arr))
+ {
+ arr = cJSON_CreateArray();
+ if (!arr)
+ return NULL;
+ cJSON_ReplaceItemInObject(root, "emojiGroups", arr);
+ }
+ return arr;
+}
+
+/* 判断是否已存在条目 */
+static int ln_groups_contains(cJSON *arr, const char *characterId, const char *eyesColor, const char *eyesShape)
+{
+ if (!arr || !cJSON_IsArray(arr))
+ return 0;
+ int count = cJSON_GetArraySize(arr);
+ for (int i = 0; i < count; ++i)
+ {
+ cJSON *item = cJSON_GetArrayItem(arr, i);
+ if (!item || !cJSON_IsObject(item))
+ continue;
+ const char *cid = NULL, *color = NULL, *shape = NULL;
+ cJSON *v = cJSON_GetObjectItem(item, "characterId");
+ if (v && cJSON_IsString(v) && v->valuestring)
+ cid = v->valuestring;
+ v = cJSON_GetObjectItem(item, "eyesColor");
+ if (v && cJSON_IsString(v) && v->valuestring)
+ color = v->valuestring;
+ v = cJSON_GetObjectItem(item, "eyesShape");
+ if (v && cJSON_IsString(v) && v->valuestring)
+ shape = v->valuestring;
+ if (cid && color && shape &&
+ strcmp(cid, characterId ? characterId : "") == 0 &&
+ strcmp(color, eyesColor ? eyesColor : "") == 0 &&
+ strcmp(shape, eyesShape ? eyesShape : "") == 0)
+ {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* 添加表情组到持久化 */
+static void ln_persist_add_emoji_group(const char *characterId, const char *eyesColor, const char *eyesShape)
+{
+ cJSON *root = ln_load_emoji_groups_root();
+ if (!root)
+ return;
+ cJSON *arr = ln_get_or_create_groups_array(root);
+ if (!arr)
+ {
+ cJSON_Delete(root);
+ return;
+ }
+ if (!ln_groups_contains(arr, characterId, eyesColor, eyesShape))
+ {
+ cJSON *item = cJSON_CreateObject();
+ if (item)
+ {
+ cJSON_AddStringToObject(item, "characterId", characterId ? characterId : "");
+ cJSON_AddStringToObject(item, "eyesColor", eyesColor ? eyesColor : "");
+ cJSON_AddStringToObject(item, "eyesShape", eyesShape ? eyesShape : "");
+ cJSON_AddItemToArray(arr, item);
+ (void)ln_save_emoji_groups_root(root);
+ }
+ }
+ cJSON_Delete(root);
+}
+
+/* 从持久化中移除表情组 */
+static void ln_persist_remove_emoji_group(const char *characterId, const char *eyesColor, const char *eyesShape)
+{
+ cJSON *root = ln_load_emoji_groups_root();
+ if (!root)
+ return;
+ cJSON *arr = ln_get_or_create_groups_array(root);
+ if (!arr)
+ {
+ cJSON_Delete(root);
+ return;
+ }
+ int count = cJSON_GetArraySize(arr);
+ for (int i = 0; i < count; ++i)
+ {
+ cJSON *item = cJSON_GetArrayItem(arr, i);
+ if (!item || !cJSON_IsObject(item))
+ continue;
+ const char *cid = NULL, *color = NULL, *shape = NULL;
+ cJSON *v = cJSON_GetObjectItem(item, "characterId");
+ if (v && cJSON_IsString(v) && v->valuestring)
+ cid = v->valuestring;
+ v = cJSON_GetObjectItem(item, "eyesColor");
+ if (v && cJSON_IsString(v) && v->valuestring)
+ color = v->valuestring;
+ v = cJSON_GetObjectItem(item, "eyesShape");
+ if (v && cJSON_IsString(v) && v->valuestring)
+ shape = v->valuestring;
+ if (cid && color && shape &&
+ strcmp(cid, characterId ? characterId : "") == 0 &&
+ strcmp(color, eyesColor ? eyesColor : "") == 0 &&
+ strcmp(shape, eyesShape ? eyesShape : "") == 0)
+ {
+ /* 删除该元素 */
+ cJSON_DeleteItemFromArray(arr, i);
+ (void)ln_save_emoji_groups_root(root);
+ break;
+ }
+ }
+ cJSON_Delete(root);
+}
+
/* 工具函数:生成表情缓存路径 */
static void ln_gen_emoji_cache_path(const EmojiPackage *pkg, const EmotionEmoji *emoji, char *path, size_t path_len)
{
else
{
downloaded_count++;
+ /* 表情进度上报,按下载成功表情数量计算 */
+ int progress = (int)(((double)downloaded_count / pkg->emojiCount) * 100);
+ push_download_progress_notification(progress);
WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] emoji %s 下载完成", pkg->emojis[i].emotion);
}
}
/* 下载完释放本次表情包占用的内存 */
ln_free_emoji_list();
+
+ /* 持久化:仅在整个表情组下载成功时记录该表情组 */
+ if (all_success)
+ {
+ /* 通知ui下载成功 */
+ push_download_success_notification(DOWNLOAD_FILE_TYPE_EMOJI);
+ ln_persist_add_emoji_group(mail.characterId, mail.eyesColor, mail.eyesShape);
+ }
}
/* 启动表情下载任务 */
// 清理资源
cJSON_Delete(root);
free(text);
+
+ /* 持久化:删除成功则从持久化列表中移除该表情组 */
+ if (ret == 0)
+ {
+ ln_persist_remove_emoji_group(del_characterId, del_eyesColor, del_eyesShape);
+ }
}
/* 7.1 上报角色表情组下载状态(支持 description) */
if (!body)
return ERRCODE_FAIL;
- HTTPC_RESULT prep = ln_http_prepare_auto(&clientData, 2048, 8 * 1024);
+ HTTPC_RESULT prep = ln_http_prepare_auto(&clientData, 2048, LN_CLIENT_PREPARE_SIZE * 2);
if (prep != HTTP_SUCCESS)
{
free(body);
clientData.postBuf = body;
clientData.postBufLen = (int)strlen(body);
clientData.postContentType = (char *)"application/json";
+
+ //打印请求体
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[EMOJI_REPORT_ALL] request body: %s", body);
HTTPC_RESULT res = HttpClientPostRequest(&client, LN_EMOJI_REPORT_ALL_URL, &clientData);
if (res != HTTP_SUCCESS)
}
int code = HttpClientGetResponseCode(&client);
+ if (code != 200)
+ {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[EMOJI_REPORT_ALL] HTTP %d", code);
+ free(body);
+ HttpClientUnprepare(&clientData);
+ free(header_buf);
+ return ERRCODE_FAIL;
+ }
if (clientData.responseBuf && clientData.responseBufLen > 0)
{
int real_len = clientData.responseContentLen > 0 ? clientData.responseContentLen : clientData.responseBufLen;
WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[EMOJI_REPORT_STATUS] response body: %s", response_buf);
free(response_buf);
}
- if (code != 200)
- {
- free(body);
- HttpClientUnprepare(&clientData);
- free(header_buf);
- return ERRCODE_FAIL;
- }
free(body);
HttpClientUnprepare(&clientData);
/* 上报所有角色表情组状态 */
void ln_emoji_report_all(void)
{
- ln_emoji_report_all_http(uapi_ln_get_device_id(),
- uapi_ln_get_device_token(),
- g_emoji_package.emojis,
- g_emoji_package.emojiCount);
+ const char *device_id = uapi_ln_get_device_id();
+ const char *device_token = uapi_ln_get_device_token();
+ if (!device_id || !device_token)
+ {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[EMOJI_REPORT_ALL] missing device id/token");
+ return;
+ }
+
+ cJSON *root = ln_load_emoji_groups_root();
+ if (!root)
+ {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[EMOJI_REPORT_ALL] load root failed");
+ return;
+ }
+ cJSON *arr = ln_get_or_create_groups_array(root);
+ int count = (arr && cJSON_IsArray(arr)) ? cJSON_GetArraySize(arr) : 0;
+ if (count < 0)
+ count = 0;
+
+ LnEmojiGroup *groups = NULL;
+ if (count > 0)
+ {
+ groups = (LnEmojiGroup *)calloc((size_t)count, sizeof(LnEmojiGroup));
+ if (!groups)
+ {
+ cJSON_Delete(root);
+ return;
+ }
+ for (int i = 0; i < count; ++i)
+ {
+ cJSON *item = cJSON_GetArrayItem(arr, i);
+ cJSON *v = NULL;
+ v = cJSON_GetObjectItem(item, "characterId");
+ groups[i].characterId = (v && cJSON_IsString(v)) ? v->valuestring : "";
+ v = cJSON_GetObjectItem(item, "eyesColor");
+ groups[i].eyesColor = (v && cJSON_IsString(v)) ? v->valuestring : "";
+ v = cJSON_GetObjectItem(item, "eyesShape");
+ groups[i].eyesShape = (v && cJSON_IsString(v)) ? v->valuestring : "";
+ groups[i].status = "download_success"; /* 当前设备上已安装的表情组 */
+ }
+ }
+
+ (void)ln_emoji_report_all_http(device_id, device_token, groups, count);
+
+ if (groups)
+ free(groups);
+ cJSON_Delete(root);
}
\ No newline at end of file