From f159d858e7f1042e6c81d2b56473ca0697009351 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BD=99=E6=96=87=E5=BB=BA?= <8997665+yu_wenjian@user.noreply.gitee.com> Date: Mon, 2 Sep 2024 15:38:46 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=A0=E9=99=A4=E5=9B=BD=E5=86=85=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=AD=98=E5=82=A8=20SDK=20V3=20=E7=89=88=E6=9C=AC?= =?UTF-8?q?=E4=B8=AD=20LiveQuery=20=E7=9B=B8=E5=85=B3=E6=8F=8F=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sdk/storage/dotnet-guide/dotnet.mdx | 172 ----- .../sdk/storage/dotnet-guide/setup-dotnet.mdx | 2 +- .../sdk/storage/java-guide/java.mdx | 253 ------ .../version-v3/sdk/storage/js-guide/js.mdx | 182 ----- .../sdk/storage/js-guide/setup-js.mdx | 727 +----------------- .../sdk/storage/objc-guide/objc.mdx | 205 ----- 6 files changed, 8 insertions(+), 1533 deletions(-) diff --git a/versioned_docs/version-v3/sdk/storage/dotnet-guide/dotnet.mdx b/versioned_docs/version-v3/sdk/storage/dotnet-guide/dotnet.mdx index 080d140ae..d18589ce3 100644 --- a/versioned_docs/version-v3/sdk/storage/dotnet-guide/dotnet.mdx +++ b/versioned_docs/version-v3/sdk/storage/dotnet-guide/dotnet.mdx @@ -728,178 +728,6 @@ LCQuery query = LCQuery.And(new LCQuery[] { priori - 无索引的排序(另外除非复合索引同时覆盖了查询和排序,否则只有其中一个能使用索引) - 无索引的查询(另外除非复合索引同时覆盖了所有条件,否则未覆盖到的条件无法使用索引,如果未覆盖的条件区分度较低将会扫描较多的数据) - - -## LiveQuery - -LiveQuery 衍生于 [`LCQuery`](#查询),并为其带来了更强大的功能。它可以让你无需编写复杂的逻辑便可在客户端之间同步数据,这对于有实时数据同步需求的应用来说很有帮助。 - -设想你正在开发一个多人协作同时编辑一份文档的应用,单纯地使用 `LCQuery` 并不是最好的做法,因为它只具备主动拉取的功能,而应用并不知道什么时候该去拉取。 - -想要解决这个问题,就要用到 LiveQuery 了。借助 LiveQuery,你可以订阅所有需要保持同步的 `LCQuery`。订阅成功后,一旦有符合 `LCQuery` 的 `LCObject` 发生变化,云端就会主动、实时地将信息通知到客户端。 - -LiveQuery 使用 WebSocket 在客户端和云端之间建立连接。WebSocket 的处理会比较复杂,而我们将其封装成了一个简单的 API 供你直接使用,无需关注背后的原理。 - -### 启用 LiveQuery - -进入 ** > 服务设置**,在 **安全设置** 里面勾选 **启用 LiveQuery**: - -```cs -using LeanCloud.LiveQuery; -``` - -### Demo - -下面是在使用了 LiveQuery 的网页应用和手机应用中分别操作,数据保持同步的效果: - - - -使用我们的「LeanTodo」微信小程序和网页应用,可以实际体验以上视频所演示的效果,步骤如下: - -1. 微信扫码,添加小程序「LeanTodo」; - - ![LeanTodo mini program](/img/leantodo-weapp-qr.jpg) - -2. 进入小程序,点击首页左下角 **设置** > **账户设置**,输入便于记忆的用户名和密码; - -3. 使用浏览器访问 ,输入刚刚在小程序中更新好的账户信息,点击 **Login**; - -4. 随意添加更改数据,查看两端的同步状态。 - -注意按以上顺序操作。在网页应用中使用 **Signup** 注册的账户无法与小程序创建的账户相关联,所以如果颠倒以上操作顺序,则无法观测到数据同步效果。 - -[LiveQuery 公开课](http://www.bilibili.com/video/av11291992/) 涵盖了许多开发者关心的问题和解答。 - -### 构建订阅 - -首先创建一个普通的 `LCQuery` 对象,添加查询条件(如有),然后进行订阅操作: - -```cs -LCQuery query = new LCQuery("Todo"); -query.WhereEqualTo("isComplete", true); -await query.Subscribe(); -// 订阅成功 -``` - -LiveQuery 不支持内嵌查询,也不支持返回指定属性。 - -订阅成功后,就可以接收到和 `LCObject` 相关的更新了。假如在另一个客户端上创建了一个 `Todo` 对象,对象的 `title` 设为 `更新作品集`,那么下面的代码可以获取到这个新的 `Todo`: - -```cs -LCQuery query = new LCQuery("Todo"); -LCLiveQuery liveQuery = await query.Subscribe(); -liveQuery.OnCreate = (obj) => { - print(obj["title"]); // 更新作品集 -}; -``` - -此时如果有人把 `Todo` 的 `content` 改为 `把我最近画的插画放上去`,那么下面的代码可以获取到本次更新: - -```cs -liveQuery.OnUpdate = (updatedTodo, updatedKeys) => { - print(updatedTodo["content"]); // 把我最近画的插画放上去 -}; -``` - -### 事件处理 - -订阅成功后,可以选择监听如下几种数据变化: - -- `create` -- `update` -- `enter` -- `leave` -- `delete` - -#### `create` 事件 - -当有新的满足 `LCQuery` 查询条件的 `LCObject` 被创建时,`create` 事件会被触发。下面的 `obj` 就是新建的 `LCObject`: - -```cs -liveQuery.OnCreate = (obj) => { - print("对象被创建。"); -}; -``` - -#### `update` 事件 - -当有满足 `LCQuery` 查询条件的 `LCObject` 被更新时,`update` 事件会被触发。下面的 `obj` 就是有更新的 `LCObject`: - -```cs -liveQuery.OnUpdate = (obj, updatedKeys) => { - print("对象被更新。"); -}; -``` - -#### `enter` 事件 - -当一个已存在的、原本不符合 `LCQuery` 查询条件的 `LCObject` 发生更新,且更新后符合查询条件,`enter` 事件会被触发。下面的 `obj` 就是进入 `LCQuery` 的 `LCObject`,其内容为该对象最新的值: - -```cs -liveQuery.OnEnter = (obj, updatedKeys) => { - print("对象进入。"); -}; -``` - -注意区分 `create` 和 `enter` 的不同行为。如果一个对象已经存在,在更新之前不符合查询条件,而在更新之后符合查询条件,那么 `enter` 事件会被触发。如果一个对象原本不存在,后来被构建了出来,那么 `create` 事件会被触发。 - -#### `leave` 事件 - -当一个已存在的、原本符合 `LCQuery` 查询条件的 `LCObject` 发生更新,且更新后不符合查询条件,`leave` 事件会被触发。下面的 `obj` 就是离开 `LCQuery` 的 `LCObject`,其内容为该对象最新的值: - -```cs -liveQuery.OnLeave = (obj, updatedKeys) => { - print("对象离开。"); -}; -``` - -#### `delete` 事件 - -当一个已存在的、原本符合 `LCQuery` 查询条件的 `LCObject` 被删除,`delete` 事件会被触发。下面的 `objId` 就是被删除的 `LCObject` 的 `objectId`: - -```cs -liveQuery.OnDelete = (objId) => { - print("对象被删除。"); -}; -``` - -### 取消订阅 - -如果不再需要接收有关 `LCQuery` 的更新,可以取消订阅。 - -```cs -await liveQuery.Unsubscribe(); -// 成功取消订阅 -``` - -### 断开连接 - -断开连接有几种情况: - -1. 网络异常或者网络切换,非预期性断开。 -2. 退出应用、关机或者打开飞行模式等,用户在应用外的操作导致断开。 - -如上几种情况开发者无需做额外的操作,只要切回应用,SDK 会自动重新订阅,数据变更会继续推送到客户端。 - -而另外一种极端情况——**当用户在移动端使用手机的进程管理工具,杀死了进程或者直接关闭了网页的情况下**,SDK 无法自动重新订阅,此时需要开发者根据实际情况实现重新订阅。 - -### LiveQuery 的注意事项 - -因为 LiveQuery 的实时性,很多用户会陷入一个误区,试着用 LiveQuery 来实现一个简单的聊天功能。 -我们不建议这样做,因为使用 LiveQuery 构建聊天服务会承担额外的存储成本,产生的费用会增加,后期维护的难度非常大(聊天记录、对话维护之类的代码会很混乱),并且云服务已经提供了即时通讯的服务。 -LiveQuery 的核心还是提供一个针对查询的推拉结合的用法,脱离设计初衷容易造成前端的模块混乱。 - - ## 文件 diff --git a/versioned_docs/version-v3/sdk/storage/dotnet-guide/setup-dotnet.mdx b/versioned_docs/version-v3/sdk/storage/dotnet-guide/setup-dotnet.mdx index d02cb7a93..7c423600a 100644 --- a/versioned_docs/version-v3/sdk/storage/dotnet-guide/setup-dotnet.mdx +++ b/versioned_docs/version-v3/sdk/storage/dotnet-guide/setup-dotnet.mdx @@ -35,7 +35,7 @@ import Path from "/src/docComponents/path"; | 名称 | 模块描述 | | ------------------------ | ------------------------------------------------ | | `LeanCloud-SDK-Storage` | 存储服务。 | -| `LeanCloud-SDK-Realtime` | 即时通信、LiveQuery 服务,依赖于存储服务。 | +| `LeanCloud-SDK-Realtime` | 即时通信依赖于存储服务。 | | `LeanCloud-SDK-Engine` | 云引擎服务,依赖于存储,适用于云引擎服务端环境。 | 如只需使用某种服务,可下载最小依赖包,减小程序体积。 diff --git a/versioned_docs/version-v3/sdk/storage/java-guide/java.mdx b/versioned_docs/version-v3/sdk/storage/java-guide/java.mdx index 25635f252..0d9c48049 100644 --- a/versioned_docs/version-v3/sdk/storage/java-guide/java.mdx +++ b/versioned_docs/version-v3/sdk/storage/java-guide/java.mdx @@ -879,259 +879,6 @@ LCQuery query = LCQuery.and(Arrays.asList(priorityQuery, timeLocationQ - 无索引的排序(另外除非复合索引同时覆盖了查询和排序,否则只有其中一个能使用索引) - 无索引的查询(另外除非复合索引同时覆盖了所有条件,否则未覆盖到的条件无法使用索引,如果未覆盖的条件区分度较低将会扫描较多的数据) - - -## LiveQuery - -LiveQuery 衍生于 [`LCQuery`](#查询),并为其带来了更强大的功能。它可以让你无需编写复杂的逻辑便可在客户端之间同步数据,这对于有实时数据同步需求的应用来说很有帮助。 - -设想你正在开发一个多人协作同时编辑一份文档的应用,单纯地使用 `LCQuery` 并不是最好的做法,因为它只具备主动拉取的功能,而应用并不知道什么时候该去拉取。 - -想要解决这个问题,就要用到 LiveQuery 了。借助 LiveQuery,你可以订阅所有需要保持同步的 `LCQuery`。订阅成功后,一旦有符合 `LCQuery` 的 `LCObject` 发生变化,云端就会主动、实时地将信息通知到客户端。 - -LiveQuery 使用 WebSocket 在客户端和云端之间建立连接。WebSocket 的处理会比较复杂,而我们将其封装成了一个简单的 API 供你直接使用,无需关注背后的原理。 - -### 启用 LiveQuery - -进入 ** > 服务设置**,在 **安全设置** 里面勾选 **启用 LiveQuery** 即可。确保即时通信模块已被添加到 `AndroidManifest.xml`: - -```xml - - - - - - - - -``` - -可以在 [SDK 安装与初始化](#sdk-安装与初始化) 中找到完整设置方法。 - -### Demo - -下面是在使用了 LiveQuery 的网页应用和手机应用中分别操作,数据保持同步的效果: - - - -使用我们的「LeanTodo」微信小程序和网页应用,可以实际体验以上视频所演示的效果,步骤如下: - -1. 微信扫码,添加小程序「LeanTodo」; - - ![LeanTodo mini program](/img/leantodo-weapp-qr.jpg) - -2. 进入小程序,点击首页左下角 **设置** > **账户设置**,输入便于记忆的用户名和密码; - -3. 使用浏览器访问 ,输入刚刚在小程序中更新好的账户信息,点击 **Login**; - -4. 随意添加更改数据,查看两端的同步状态。 - -注意按以上顺序操作。在网页应用中使用 **Signup** 注册的账户无法与小程序创建的账户相关联,所以如果颠倒以上操作顺序,则无法观测到数据同步效果。 - -[LiveQuery 公开课](http://www.bilibili.com/video/av11291992/) 涵盖了许多开发者关心的问题和解答。 - -### 构建订阅 - -首先创建一个普通的 `LCQuery` 对象,添加查询条件(如有),然后进行订阅操作: - -```java -LCQuery query = new LCQuery<>("Todo"); -query.whereEqualTo("isComplete", true); -LCLiveQuery liveQuery = LCLiveQuery.initWithQuery(query); -liveQuery.subscribeInBackground(new LCLiveQuerySubscribeCallback() { - @Override - public void done(LCException e) { - if (e == null) { - // 订阅成功 - } - } -}); -``` - -LiveQuery 不支持内嵌查询,也不支持返回指定属性。 - -订阅成功后,就可以接收到和 `LCObject` 相关的更新了。假如在另一个客户端上创建了一个 `Todo` 对象,对象的 `title` 设为 `更新作品集`,那么下面的代码可以获取到这个新的 `Todo`: - -```java -LCQuery query = new LCQuery<>("Todo"); -query.whereEqualTo("isComplete", true); -LCLiveQuery liveQuery = LCLiveQuery.initWithQuery(query); -liveQuery.setEventHandler(new LCLiveQueryEventHandler() { - @Override - public void onObjectCreated(LCObject newTodo) { - System.out.println(newTodo.getString("title")); // 更新作品集 - } -}); -liveQuery.subscribeInBackground(new LCLiveQuerySubscribeCallback() { - @Override - public void done(LCException e) { - if (e == null) { - // 订阅成功 - } - } -}); -``` - -此时如果有人把 `Todo` 的 `content` 改为 `把我最近画的插画放上去`,那么下面的代码可以获取到本次更新: - -```java -liveQuery.setEventHandler(new LCLiveQueryEventHandler() { - @Override - public void onObjectUpdated(LCObject updatedTodo, List updatedKeys) { - System.out.println(updatedTodo.getString("content")); // 把我最近画的插画放上去 - } -}); -``` - -### 事件处理 - -订阅成功后,可以选择监听如下几种数据变化: - -- `create` -- `update` -- `enter` -- `leave` -- `delete` - -#### `create` 事件 - -当有新的满足 `LCQuery` 查询条件的 `LCObject` 被创建时,`create` 事件会被触发。下面的 `object` 就是新建的 `LCObject`: - -```java -liveQuery.setEventHandler(new LCLiveQueryEventHandler() { - @Override - public void onObjectCreated(LCObject object) { - System.out.println("对象被创建。"); - } -}); -``` - -#### `update` 事件 - -当有满足 `LCQuery` 查询条件的 `LCObject` 被更新时,`update` 事件会被触发。下面的 `object` 就是有更新的 `LCObject`: - -```java -liveQuery.setEventHandler(new LCLiveQueryEventHandler() { - @Override - public void onObjectUpdated(LCObject object, List updatedKeys) { - System.out.println("对象被更新。"); - } -}); -``` - -#### `enter` 事件 - -当一个已存在的、原本不符合 `LCQuery` 查询条件的 `LCObject` 发生更新,且更新后符合查询条件,`enter` 事件会被触发。下面的 `object` 就是进入 `LCQuery` 的 `LCObject`,其内容为该对象最新的值: - -```java -liveQuery.setEventHandler(new LCLiveQueryEventHandler() { - @Override - public void onObjectEnter(LCObject object, List updatedKeys) { - System.out.println("对象进入。"); - } -}); -``` - -注意区分 `create` 和 `enter` 的不同行为。如果一个对象已经存在,在更新之前不符合查询条件,而在更新之后符合查询条件,那么 `enter` 事件会被触发。如果一个对象原本不存在,后来被构建了出来,那么 `create` 事件会被触发。 - -#### `leave` 事件 - -当一个已存在的、原本符合 `LCQuery` 查询条件的 `LCObject` 发生更新,且更新后不符合查询条件,`leave` 事件会被触发。下面的 `object` 就是离开 `LCQuery` 的 `LCObject`,其内容为该对象最新的值: - -```java -liveQuery.setEventHandler(new LCLiveQueryEventHandler() { - @Override - public void onObjectLeave(LCObject object, List updatedKeys) { - System.out.println("对象离开。"); - } -}); -``` - -#### `delete` 事件 - -当一个已存在的、原本符合 `LCQuery` 查询条件的 `LCObject` 被删除,`delete` 事件会被触发。下面的 `object` 就是被删除的 `LCObject` 的 `objectId`: - -```java -liveQuery.setEventHandler(new LCLiveQueryEventHandler() { - @Override - public void onObjectDeleted(String object) { - System.out.println("对象被删除。"); - } -}); -``` - -### 取消订阅 - -如果不再需要接收有关 `LCQuery` 的更新,可以取消订阅。 - -```java -liveQuery.unsubscribeInBackground(new LCLiveQuerySubscribeCallback() { - @Override - public void done(LCException e) { - if (e == null) { - // 成功取消订阅 - } - } -}); -``` - -### 断开连接 - -断开连接有几种情况: - -1. 网络异常或者网络切换,非预期性断开。 -2. 退出应用、关机或者打开飞行模式等,用户在应用外的操作导致断开。 - -如上几种情况开发者无需做额外的操作,只要切回应用,SDK 会自动重新订阅,数据变更会继续推送到客户端。 - -而另外一种极端情况——**当用户在移动端使用手机的进程管理工具,杀死了进程或者直接关闭了网页的情况下**,SDK 无法自动重新订阅,此时需要开发者根据实际情况实现重新订阅。 - -### 网络状态响应 - -可以调用 `setConnectionHandler` 静态方法监听 LiveQuery 连接的建立、断开、异常: - -```java -LCLiveQuery.setConnectionHandler(new LCLiveQueryConnectionHandler() { - @Override - public void onConnectionOpen() { - System.out.println("============ LiveQuery Connection opened ============"); - } - - @Override - public void onConnectionClose() { - System.out.println("============ LiveQuery Connection closed ============"); - } - - @Override - public void onConnectionError(int code, String reason) { - System.out.println("============ LiveQuery Connection error. code:" + code - + ", reason:" + reason + " ============"); - } -}); -``` - -### LiveQuery 的注意事项 - -因为 LiveQuery 的实时性,很多用户会陷入一个误区,试着用 LiveQuery 来实现一个简单的聊天功能。 -我们不建议这样做,因为使用 LiveQuery 构建聊天服务会承担额外的存储成本,产生的费用会增加,后期维护的难度非常大(聊天记录、对话维护之类的代码会很混乱),并且云服务已经提供了即时通讯的服务。 -LiveQuery 的核心还是提供一个针对查询的推拉结合的用法,脱离设计初衷容易造成前端的模块混乱。 - -如果你的应用只使用 LiveQuery(不使用即时通讯和其他推送服务),那么可以在初始化 SDK 时使用 `PushService` 的静态方法 `startIfRequired` 来创建 WebSocket 连接: - -```java -PushService.startIfRequired(android.content.Context context); -``` - ## 文件 diff --git a/versioned_docs/version-v3/sdk/storage/js-guide/js.mdx b/versioned_docs/version-v3/sdk/storage/js-guide/js.mdx index 1a000168a..c24e7c3ff 100644 --- a/versioned_docs/version-v3/sdk/storage/js-guide/js.mdx +++ b/versioned_docs/version-v3/sdk/storage/js-guide/js.mdx @@ -901,188 +901,6 @@ const query = AV.Query.and(priorityQuery, timeLocationQuery); - 无索引的排序(另外除非复合索引同时覆盖了查询和排序,否则只有其中一个能使用索引) - 无索引的查询(另外除非复合索引同时覆盖了所有条件,否则未覆盖到的条件无法使用索引,如果未覆盖的条件区分度较低将会扫描较多的数据) - - -## LiveQuery - -LiveQuery 衍生于 [`AV.Query`](#查询),并为其带来了更强大的功能。它可以让你无需编写复杂的逻辑便可在客户端之间同步数据,这对于有实时数据同步需求的应用来说很有帮助。 - -设想你正在开发一个多人协作同时编辑一份文档的应用,单纯地使用 `AV.Query` 并不是最好的做法,因为它只具备主动拉取的功能,而应用并不知道什么时候该去拉取。 - -想要解决这个问题,就要用到 LiveQuery 了。借助 LiveQuery,你可以订阅所有需要保持同步的 `AV.Query`。订阅成功后,一旦有符合 `AV.Query` 的 `AV.Object` 发生变化,云端就会主动、实时地将信息通知到客户端。 - -LiveQuery 使用 WebSocket 在客户端和云端之间建立连接。WebSocket 的处理会比较复杂,而我们将其封装成了一个简单的 API 供你直接使用,无需关注背后的原理。 - -### 启用 LiveQuery - -进入 ** > 服务设置**,在 **安全设置** 里面勾选 **启用 LiveQuery**,然后将下面的 npm 模块添加到项目中即可: - -```js -// 无需加载 leancloud-storage -const AV = require("leancloud-storage/live-query"); -``` - -或者使用 `script` 标签: - - -{` -`} - - -### Demo - -下面是在使用了 LiveQuery 的网页应用和手机应用中分别操作,数据保持同步的效果: - - - -使用我们的「LeanTodo」微信小程序和网页应用,可以实际体验以上视频所演示的效果,步骤如下: - -1. 微信扫码,添加小程序「LeanTodo」; - - ![LeanTodo mini program](/img/leantodo-weapp-qr.jpg) - -2. 进入小程序,点击首页左下角 **设置** > **账户设置**,输入便于记忆的用户名和密码; - -3. 使用浏览器访问 ,输入刚刚在小程序中更新好的账户信息,点击 **Login**; - -4. 随意添加更改数据,查看两端的同步状态。 - -注意按以上顺序操作。在网页应用中使用 **Signup** 注册的账户无法与小程序创建的账户相关联,所以如果颠倒以上操作顺序,则无法观测到数据同步效果。 - -[LiveQuery 公开课](http://www.bilibili.com/video/av11291992/) 涵盖了许多开发者关心的问题和解答。 - -### 构建订阅 - -首先创建一个普通的 `AV.Query` 对象,添加查询条件(如有),然后进行订阅操作: - -```js -const query = new AV.Query("Todo"); -query.subscribe().then((liveQuery) => { - // 订阅成功 -}); -``` - -LiveQuery 不支持内嵌查询,也不支持返回指定属性。 - -订阅成功后,就可以接收到和 `AV.Object` 相关的更新了。假如在另一个客户端上创建了一个 `Todo` 对象,对象的 `title` 设为 `更新作品集`,那么下面的代码可以获取到这个新的 `Todo`: - -```js -const query = new AV.Query("Todo"); -query.subscribe().then((liveQuery) => { - liveQuery.on("create", (newTodo) => { - console.log(newTodo.get("title")); // 更新作品集 - }); -}); -``` - -此时如果有人把 `Todo` 的 `content` 改为 `把我最近画的插画放上去`,那么下面的代码可以获取到本次更新: - -```js -liveQuery.on("update", (updatedTodo, updatedKeys) => { - console.log(updatedTodo.get("content")); // 把我最近画的插画放上去 -}); -``` - -### 事件处理 - -订阅成功后,可以选择监听如下几种数据变化: - -- `create` -- `update` -- `enter` -- `leave` -- `delete` - -#### `create` 事件 - -当有新的满足 `AV.Query` 查询条件的 `AV.Object` 被创建时,`create` 事件会被触发。下面的 `object` 就是新建的 `AV.Object`: - -```js -liveQuery.on("create", (object) => { - console.log("对象被创建。"); -}); -``` - -#### `update` 事件 - -当有满足 `AV.Query` 查询条件的 `AV.Object` 被更新时,`update` 事件会被触发。下面的 `object` 就是有更新的 `AV.Object`: - -```js -liveQuery.on("update", (object, updatedKeys) => { - console.log("对象被更新。"); -}); -``` - -#### `enter` 事件 - -当一个已存在的、原本不符合 `AV.Query` 查询条件的 `AV.Object` 发生更新,且更新后符合查询条件,`enter` 事件会被触发。下面的 `object` 就是进入 `AV.Query` 的 `AV.Object`,其内容为该对象最新的值: - -```js -liveQuery.on("enter", (object, updatedKeys) => { - console.log("对象进入。"); -}); -``` - -注意区分 `create` 和 `enter` 的不同行为。如果一个对象已经存在,在更新之前不符合查询条件,而在更新之后符合查询条件,那么 `enter` 事件会被触发。如果一个对象原本不存在,后来被构建了出来,那么 `create` 事件会被触发。 - -#### `leave` 事件 - -当一个已存在的、原本符合 `AV.Query` 查询条件的 `AV.Object` 发生更新,且更新后不符合查询条件,`leave` 事件会被触发。下面的 `object` 就是离开 `AV.Query` 的 `AV.Object`,其内容为该对象最新的值: - -```js -liveQuery.on("leave", (object, updatedKeys) => { - console.log("对象离开。"); -}); -``` - -#### `delete` 事件 - -当一个已存在的、原本符合 `AV.Query` 查询条件的 `AV.Object` 被删除,`delete` 事件会被触发。下面的 `object` 就是被删除的 `AV.Object` 的 `objectId`: - -```js -liveQuery.on("delete", (object) => { - console.log("对象被删除。"); -}); -``` - -### 取消订阅 - -如果不再需要接收有关 `AV.Query` 的更新,可以取消订阅。 - -```js -liveQuery.unsubscribe().then(() => { - // 成功取消订阅 -}); -``` - -### 断开连接 - -断开连接有几种情况: - -1. 网络异常或者网络切换,非预期性断开。 -2. 退出应用、关机或者打开飞行模式等,用户在应用外的操作导致断开。 - -如上几种情况开发者无需做额外的操作,只要切回应用,SDK 会自动重新订阅,数据变更会继续推送到客户端。 - -而另外一种极端情况——**当用户在移动端使用手机的进程管理工具,杀死了进程或者直接关闭了网页的情况下**,SDK 无法自动重新订阅,此时需要开发者根据实际情况实现重新订阅。 - -### LiveQuery 的注意事项 - -因为 LiveQuery 的实时性,很多用户会陷入一个误区,试着用 LiveQuery 来实现一个简单的聊天功能。 -我们不建议这样做,因为使用 LiveQuery 构建聊天服务会承担额外的存储成本,产生的费用会增加,后期维护的难度非常大(聊天记录、对话维护之类的代码会很混乱),并且云服务已经提供了即时通讯的服务。 -LiveQuery 的核心还是提供一个针对查询的推拉结合的用法,脱离设计初衷容易造成前端的模块混乱。 - - ## 文件 diff --git a/versioned_docs/version-v3/sdk/storage/js-guide/setup-js.mdx b/versioned_docs/version-v3/sdk/storage/js-guide/setup-js.mdx index 3694f0578..de7fb330d 100644 --- a/versioned_docs/version-v3/sdk/storage/js-guide/setup-js.mdx +++ b/versioned_docs/version-v3/sdk/storage/js-guide/setup-js.mdx @@ -118,27 +118,6 @@ import { CardGrid, Card } from "/src/docComponents/doc"; $ npm install leancloud-storage --save ``` - - - -``` -$ npm install leancloud-storage --save -``` - - - - -``` -$ npm install leancloud-realtime --save -``` - - - - -``` -$ npm install leancloud-realtime leancloud-realtime-plugin-typed-messages leancloud-storage --save -``` - @@ -154,60 +133,6 @@ const AV = require("leancloud-storage"); const { Query, User } = AV; ``` - - - -```js -const AV = require("leancloud-storage/live-query"); -const { Query, User } = AV; -``` - - - - -```js -const { Realtime, TextMessage } = require("leancloud-realtime"); -``` - -为了保证兼容性,SDK 一直以来分发的都是 ECMAScript 5 版本的代码,并打包了所有需要的 Polyfills(比如 Promise)。 -即时通讯 SDK v5.0.0-rc.2 起同时提供以最新版本 ECMAScript 为编译目标的版本,该版本拥有更小的体积与更好的运行时优化,适用于只需要兼容最新版本浏览器的使用场景。 -如果应用使用了 `@babel/preset-env` 或类似方案,也可以在转译时 include 最新 ECMAScript 版本的 SDK,由应用来决定要兼容的目标运行环境。 -需要注意最新版本 ECMAScript 每年都会变,而该版本的目标即是提供与最新标准对齐的代码,因此由于引入了新版本 ECMASCript 特性导致不再支持某些非最新版本的运行环境将不被视为破坏兼容性的改动。 -当前 ECMAScript 的版本为 2020。 - -如果想要试用这一功能,可以通过以下方式引入即时通讯 SDK: - -```js -const { Realtime } = require("leancloud-realtime/es-latest"); -``` - - - - -```js -const AV = require("leancloud-storage"); -const IM = require("leancloud-realtime"); - -const initPlugin = require("leancloud-realtime-plugin-typed-messages"); - -const { Realtime, TextMessage } = IM; -const { TypedMessagesPlugin, ImageMessage } = initPlugin(AV, IM); -``` - -富媒体消息插件包含的消息类型可以参考 [富媒体消息插件 API 文档](https://leancloud.github.io/js-realtime-sdk/plugins/typed-messages/docs/module-leancloud-realtime-plugin-typed-messages.html)。 - -为了保证兼容性,SDK 一直以来分发的都是 ECMAScript 5 版本的代码,并打包了所有需要的 Polyfills(比如 Promise)。 -即时通讯 SDK v5.0.0-rc.2 起同时提供以最新版本 ECMAScript 为编译目标的版本,该版本拥有更小的体积与更好的运行时优化,适用于只需要兼容最新版本浏览器的使用场景。 -如果应用使用了 `@babel/preset-env` 或类似方案,也可以在转译时 include 最新 ECMAScript 版本的 SDK,由应用来决定要兼容的目标运行环境。 -需要注意最新版本 ECMAScript 每年都会变,而该版本的目标即是提供与最新标准对齐的代码,因此由于引入了新版本 ECMASCript 特性导致不再支持某些非最新版本的运行环境将不被视为破坏兼容性的改动。 -当前 ECMAScript 的版本为 2020。 - -如果想要试用这一功能,可以通过以下方式引入即时通讯 SDK: - -```js -const { Realtime } = require("leancloud-realtime/es-latest"); -``` - @@ -228,29 +153,6 @@ const { Realtime } = require("leancloud-realtime/es-latest"); {``} - - - - - {``} - - - - - - - {``} - - - - - - - {` - -`} - - @@ -263,33 +165,6 @@ const { Realtime } = require("leancloud-realtime/es-latest"); const { Query, User } = AV; ``` - - - -```js -const { Query, User } = AV; -``` - - - - -```js -const { Realtime, TextMessage } = AV; -``` - -如果想要试用以最新版本 ECMAScript 为编译目标的即时通讯 SDK 版本(参见 [npm](#npm) 章节的说明),可以这样加载文件: - - - {``} - - - - - -```js -const { Realtime, TextMessage, TypedMessagesPlugin, ImageMessage } = AV; -``` - @@ -321,25 +196,6 @@ QQ 小程序兼容微信小程序的 API,因此两者使用同一个 SDK,安 前往 [存储 SDK 下载页](https://releases.leanapp.cn/#/leancloud/javascript-sdk/releases),下载最新版本的 `av-core-min.js`,移动到 `libs` 目录。 - - - -前往 [存储 SDK 下载页](https://releases.leanapp.cn/#/leancloud/javascript-sdk/releases),下载最新版本的 `av-live-query-core-min.js`,移动到 `libs` 目录。 - - - - -前往 [即时通讯 SDK 下载页](https://releases.leanapp.cn/#/leancloud/js-realtime-sdk/releases),下载最新版本的 `im.min.js`,移动到 `libs` 目录。 - - - - -前往 [存储 SDK 下载页](https://releases.leanapp.cn/#/leancloud/javascript-sdk/releases),下载最新版本的 `av-core-min.js`,移动到 `libs` 目录,并将文件重命名为 `leancloud-storage.js`。 - -前往 [即时通讯 SDK 下载页](https://releases.leanapp.cn/#/leancloud/js-realtime-sdk/releases),下载最新版本的 `im.min.js`,移动到 `libs` 目录,并将文件重命名为 `leancloud-realtime.js`。 - -下载 [`typed-messages.min.js`](https://code.bdstatic.com/npm/leancloud-realtime-plugin-typed-messages@4.0.2/dist/typed-messages.min.js),移动到 `libs` 目录。 - @@ -363,43 +219,6 @@ const adapters = require("./libs/leancloud-adapters-weapp.js"); AV.setAdapters(adapters); ``` - - - -```js -const AV = require("./libs/av-live-query-core-min.js"); -const adapters = require("./libs/leancloud-adapters-weapp.js"); - -AV.setAdapters(adapters); -``` - - - - -```js -const { Realtime, TextMessage, setAdapters } = require("./libs/im.min.js"); -const adapters = require("./libs/leancloud-adapters-weapp.js"); - -setAdapters(adapters); -``` - - - - -```js -// 需要保证依次加载三个文件 -const AV = require("./libs/leancloud-storage.js"); -const IM = require("./libs/leancloud-realtime.js"); -const initPlugin = require("./libs/typed-messages.min.js"); -const adapters = require("./libs/leancloud-adapters-weapp.js"); - -const { Realtime, TextMessage } = IM; -const { TypedMessagesPlugin, ImageMessage } = initPlugin(AV, IM); - -AV.setAdapters(adapters); // 为存储 SDK 设置 adapters -IM.setAdapters(adapters); // 为即时通讯 SDK 设置 adapters -``` - @@ -444,27 +263,6 @@ import AV from "leancloud-storage/dist/av-weapp.js"; $ npm install leancloud-storage @leancloud/platform-adapters-alipay ``` - - - -``` -$ npm install leancloud-storage @leancloud/platform-adapters-alipay -``` - - - - -``` -$ npm install leancloud-realtime @leancloud/platform-adapters-alipay -``` - - - - -``` -$ npm install leancloud-realtime leancloud-realtime-plugin-typed-messages leancloud-storage @leancloud/platform-adapters-alipay -``` - @@ -480,42 +278,6 @@ const adapters = require("@leancloud/platform-adapters-alipay"); AV.setAdapters(adapters); ``` - - - -```js -const AV = require("leancloud-storage/live-query-core"); -const adapters = require("@leancloud/platform-adapters-alipay"); - -AV.setAdapters(adapters); -``` - - - - -```js -const { Realtime, setAdapters } = require("leancloud-realtime/im"); -const adapters = require("@leancloud/platform-adapters-alipay"); - -setAdapters(adapters); -``` - - - - -```js -const AV = require("leancloud-storage/core"); -const IM = require("leancloud-realtime/im"); -const initPlugin = require("leancloud-realtime-plugin-typed-messages"); -const adapters = require("@leancloud/platform-adapters-alipay"); - -const { Realtime, TextMessage } = IM; -const { TypedMessagesPlugin, ImageMessage } = initPlugin(AV, IM); - -AV.setAdapters(adapters); // 为存储 SDK 设置 adapters -IM.setAdapters(adapters); // 为即时通讯 SDK 设置 adapters -``` - @@ -532,27 +294,6 @@ IM.setAdapters(adapters); // 为即时通讯 SDK 设置 adapters $ npm install leancloud-storage @leancloud/platform-adapters-baidu ``` - - - -``` -$ npm install leancloud-storage @leancloud/platform-adapters-baidu -``` - - - - -``` -$ npm install leancloud-realtime @leancloud/platform-adapters-baidu -``` - - - - -``` -$ npm install leancloud-realtime leancloud-realtime-plugin-typed-messages leancloud-storage @leancloud/platform-adapters-baidu -``` - @@ -568,42 +309,6 @@ const adapters = require("@leancloud/platform-adapters-baidu"); AV.setAdapters(adapters); ``` - - - -```js -const AV = require("leancloud-storage/live-query-core"); -const adapters = require("@leancloud/platform-adapters-baidu"); - -AV.setAdapters(adapters); -``` - - - - -```js -const { Realtime, setAdapters } = require("leancloud-realtime/im"); -const adapters = require("@leancloud/platform-adapters-baidu"); - -setAdapters(adapters); -``` - - - - -```js -const AV = require("leancloud-storage/core"); -const IM = require("leancloud-realtime/im"); -const initPlugin = require("leancloud-realtime-plugin-typed-messages"); -const adapters = require("@leancloud/platform-adapters-baidu"); - -const { Realtime, TextMessage } = IM; -const { TypedMessagesPlugin, ImageMessage } = initPlugin(AV, IM); - -AV.setAdapters(adapters); // 为存储 SDK 设置 adapters -IM.setAdapters(adapters); // 为即时通讯 SDK 设置 adapters -``` - @@ -614,25 +319,6 @@ IM.setAdapters(adapters); // 为即时通讯 SDK 设置 adapters 前往 [存储 SDK 下载页](https://releases.leanapp.cn/#/leancloud/javascript-sdk/releases),下载最新版本的 `av-core-min.js`,移动到 `libs` 目录。 - - - -前往 [存储 SDK 下载页](https://releases.leanapp.cn/#/leancloud/javascript-sdk/releases),下载最新版本的 `av-live-query-core-min.js`,移动到 `libs` 目录。 - - - - -前往 [即时通讯 SDK 下载页](https://releases.leanapp.cn/#/leancloud/js-realtime-sdk/releases),下载最新版本的 `im.min.js`,移动到 `libs` 目录。 - - - - -前往 [存储 SDK 下载页](https://releases.leanapp.cn/#/leancloud/javascript-sdk/releases),下载最新版本的 `av-core-min.js`,移动到 `libs` 目录,并将文件重命名为 `leancloud-storage.js`。 - -前往 [即时通讯 SDK 下载页](https://releases.leanapp.cn/#/leancloud/js-realtime-sdk/releases),下载最新版本的 `im.min.js`,移动到 `libs` 目录,并将文件重命名为 `leancloud-realtime.js`。 - -下载 [`typed-messages.min.js`](https://code.bdstatic.com/npm/leancloud-realtime-plugin-typed-messages@4.0.2/dist/typed-messages.min.js),移动到 `libs` 目录。 - @@ -656,43 +342,6 @@ const adapters = require("./libs/leancloud-adapters-toutiao.js"); AV.setAdapters(adapters); ``` - - - -```js -const AV = require("./libs/av-live-query-core-min.js"); -const adapters = require("./libs/leancloud-adapters-toutiao.js"); - -AV.setAdapters(adapters); -``` - - - - -```js -const { Realtime, TextMessage, setAdapters } = require("./libs/im.min.js"); -const adapters = require("./libs/leancloud-adapters-toutiao.js"); - -setAdapters(adapters); -``` - - - - -```js -// 需要保证依次加载三个文件 -const AV = require("./libs/leancloud-storage.js"); -const IM = require("./libs/leancloud-realtime.js"); -const initPlugin = require("./libs/typed-messages.min.js"); -const adapters = require("./libs/leancloud-adapters-toutiao.js"); - -const { Realtime, TextMessage } = IM; -const { TypedMessagesPlugin, ImageMessage } = initPlugin(AV, IM); - -AV.setAdapters(adapters); // 为存储 SDK 设置 adapters -IM.setAdapters(adapters); // 为即时通讯 SDK 设置 adapters -``` - @@ -717,31 +366,6 @@ CocosCreator 项目默认没有 `package.json` 文件,可以在安装 SDK 前 + const AV = require('leancloud-storage/dist/av-weapp-min.js'); ``` - - - -```diff -// SDK 应用路径变更为 -- const AV = require('leancloud-storage/live-query'); -+ const AV = require('leancloud-storage/dist/av-live-query-weapp-min.js'); -``` - - - - -```diff -// SDK 应用路径变更为 -- const { Realtime } = require('leancloud-realtime'); -+ const { Realtime } = require('leancloud-realtime/dist/im-weapp.js'); -``` - - - - -```diff -// 暂不支持 -``` - @@ -771,78 +395,23 @@ LayaAir 项目默认没有 `package.json` 文件,可以在安装 SDK 前通过 - -``` -$ npm install leancloud-storage @leancloud/platform-adapters-quickapp --save -``` - - - - -``` -$ npm install leancloud-storage @leancloud/platform-adapters-quickapp --save -``` - - - - -``` -$ npm install leancloud-realtime @leancloud/platform-adapters-quickapp --save -``` - - - - -``` -$ npm install leancloud-realtime leancloud-realtime-plugin-typed-messages leancloud-storage @leancloud/platform-adapters-quickapp --save -``` - - - - -获得引用: - - - - -```js -const AV = require("leancloud-storage/core"); -const adapters = require("@leancloud/platform-adapters-quickapp"); -AV.setAdapters(adapters); -``` - - - - -```js -const AV = require("leancloud-storage/live-query-core"); -const adapters = require("@leancloud/platform-adapters-quickapp"); -AV.setAdapters(adapters); + +``` +$ npm install leancloud-storage @leancloud/platform-adapters-quickapp --save ``` - + -```js -const { Realtime, setAdapters } = require("leancloud-realtime/im"); -const adapters = require("@leancloud/platform-adapters-quickapp"); -setAdapters(adapters); -``` +获得引用: - - + + ```js const AV = require("leancloud-storage/core"); -const IM = require("leancloud-realtime/im"); -const initPlugin = require("leancloud-realtime-plugin-typed-messages"); - -const { Realtime, TextMessage } = IM; -const { TypedMessagesPlugin, ImageMessage } = initPlugin(AV, IM); - const adapters = require("@leancloud/platform-adapters-quickapp"); AV.setAdapters(adapters); -IM.setAdapters(adapters); ``` @@ -869,43 +438,6 @@ $ npx pod-install # For Expo (SDK >= 38) 无需 link ``` - - - -``` -# Step 1: Install -$ yarn add leancloud-storage @leancloud/platform-adapters-react-native @react-native-community/async-storage@1 - -# Step 2: Link -# For React Native 0.60+ -$ npx pod-install -# For React Native <= 0.59 -# npx react-native link @react-native-community/async-storage -# For Expo (SDK >= 38) 无需 link -``` - - - - -``` -$ yarn add leancloud-realtime @leancloud/platform-adapters-react-native -``` - - - - -``` -# Step 1: Install -$ yarn add leancloud-realtime leancloud-realtime-plugin-typed-messages leancloud-storage @leancloud/platform-adapters-react-native @react-native-community/async-storage@1 - -# Step 2: Link -# For React Native 0.60+ -$ npx pod-install -# For React Native <= 0.59 -# npx react-native link @react-native-community/async-storage -# For Expo (SDK >= 38) 无需 link -``` - @@ -920,40 +452,6 @@ import * as adapters from "@leancloud/platform-adapters-react-native"; AV.setAdapters(adapters); ``` - - - -```js -import AV from "leancloud-storage/live-query-core"; -import * as adapters from "@leancloud/platform-adapters-react-native"; -AV.setAdapters(adapters); -``` - - - - -```js -import { Realtime, setAdapters } from "leancloud-realtime/im"; -import * as adapters from "@leancloud/platform-adapters-react-native"; -setAdapters(adapters); -``` - - - - -```js -import AV from "leancloud-storage/core"; -import IM from "leancloud-realtime/im"; -import initPlugin from "leancloud-realtime-plugin-typed-messages"; -import * as adapters from "@leancloud/platform-adapters-react-native"; - -const { Realtime, TextMessage } = IM; -const { TypedMessagesPlugin, ImageMessage } = initPlugin(AV, IM); - -AV.setAdapters(adapters); -IM.setAdapters(adapters); -``` - @@ -968,27 +466,6 @@ Electron 使用包管理工具 npm 管理依赖,你可以通过以下命令安 $ npm install leancloud-storage --save ``` - - - -``` -$ npm install leancloud-storage --save -``` - - - - -``` -$ npm install leancloud-realtime --save -``` - - - - -``` -$ npm install leancloud-realtime leancloud-realtime-plugin-typed-messages leancloud-storage --save -``` - @@ -1003,29 +480,6 @@ $ npm install leancloud-realtime leancloud-realtime-plugin-typed-messages leancl ``` - - - -```html - -``` - - - - -```html - -``` - - - - -```html - - - -``` - @@ -1055,40 +509,6 @@ const adapters = require("platform-adapters-xyz"); AV.setAdapters(adapters); ``` - - - -```js -const AV = require("leancloud-storage/live-query-core"); -const adapters = require("platform-adapters-xyz"); -AV.setAdapters(adapters); -``` - - - - -```js -const { Realtime, setAdapters } = require("leancloud-realtime/im"); -const adapters = require("platform-adapters-xyz"); -setAdapters(adapters); -``` - - - - -```js -const AV = require("leancloud-storage/core"); -const IM = require("leancloud-realtime/im"); -const initPlugin = require("leancloud-realtime-plugin-typed-messages"); -const adapters = require("platform-adapters-xyz"); - -const { Realtime, TextMessage } = IM; -const { TypedMessagesPlugin, ImageMessage } = initPlugin(AV, IM); - -AV.setAdapters(adapters); -IM.setAdapters(adapters); -``` - @@ -1101,27 +521,6 @@ IM.setAdapters(adapters); {`https://code.bdstatic.com/npm/leancloud-storage@${v3SDKVersions.leancloud.js.storage}/dist/av-core-min.js`} - - - - - {`https://code.bdstatic.com/npm/leancloud-storage@${v3SDKVersions.leancloud.js.storage}/dist/av-live-query-core-min.js`} - - - - - - - {`https://code.bdstatic.com/npm/leancloud-realtime@${v3SDKVersions.leancloud.js.realtime}/dist/im.min.js`} - - - - - -``` -// 不支持该方式 -``` - @@ -1145,47 +544,7 @@ AV.init({ ``` - - -```js -AV.init({ - appId: "your-client-id", - appKey: "your-client-token", - serverURL: "https://your_server_url", -}); -``` - - - - -```js -const realtime = new Realtime({ - appId: "your-client-id", - appKey: "your-client-token", - server: "https://your_server_url", -}); -``` - - - - -```js -const realtime = new Realtime({ - appId: "your-client-id", - appKey: "your-client-token", - server: "https://your_server_url", - // 初始化即时通讯服务时需要指定富媒体消息插件 - plugins: [TypedMessagesPlugin], -}); -// 需要同时初始化存储服务 -AV.init({ - appId: "your-client-id", - appKey: "your-client-token", - serverURL: "https://your_server_url", -}); -``` - @@ -1270,27 +629,6 @@ AV.init({ DEBUG=leancloud* npm start ``` - - - -``` -DEBUG=leancloud*,LC* npm start -``` - - - - -``` -DEBUG=LC* npm start -``` - - - - -``` -DEBUG=LC* npm start -``` - @@ -1303,27 +641,6 @@ DEBUG=LC* npm start localStorage.setItem('debug', 'leancloud*'); ``` - - - -``` -localStorage.setItem('debug', 'leancloud*,LC*'); -``` - - - - -``` -localStorage.setItem('debug', 'LC*'); -``` - - - - -``` -localStorage.setItem('debug', 'LC*'); -``` - @@ -1339,36 +656,6 @@ AV.debug.enable(); // 启用 AV.debug.disable(); // 停用 ``` - - - -```js -// 需要 SDK 版本 >= v3.14.0 -const AV = require("leancloud-storage"); -AV.debug.enable(); // 启用 -AV.debug.disable(); // 停用 -``` - - - - -```js -// 需要 SDK 版本 >= v5.0.0-alpha.1 -const { debug } = require("leancloud-realtime"); -debug.enable(); // 启用 -debug.disable(); // 停用 -``` - - - - -```js -// 需要 SDK 版本 >= v5.0.0-alpha.1 -const { debug } = require("leancloud-realtime"); -debug.enable(); // 启用 -debug.disable(); // 停用 -``` - diff --git a/versioned_docs/version-v3/sdk/storage/objc-guide/objc.mdx b/versioned_docs/version-v3/sdk/storage/objc-guide/objc.mdx index 020905689..2893774fb 100644 --- a/versioned_docs/version-v3/sdk/storage/objc-guide/objc.mdx +++ b/versioned_docs/version-v3/sdk/storage/objc-guide/objc.mdx @@ -857,211 +857,6 @@ query.maxCacheAge = 24*3600; - 无索引的排序(另外除非复合索引同时覆盖了查询和排序,否则只有其中一个能使用索引) - 无索引的查询(另外除非复合索引同时覆盖了所有条件,否则未覆盖到的条件无法使用索引,如果未覆盖的条件区分度较低将会扫描较多的数据) - - -## LiveQuery - -LiveQuery 衍生于 [`LCQuery`](#查询),并为其带来了更强大的功能。它可以让你无需编写复杂的逻辑便可在客户端之间同步数据,这对于有实时数据同步需求的应用来说很有帮助。 - -设想你正在开发一个多人协作同时编辑一份文档的应用,单纯地使用 `LCQuery` 并不是最好的做法,因为它只具备主动拉取的功能,而应用并不知道什么时候该去拉取。 - -想要解决这个问题,就要用到 LiveQuery 了。借助 LiveQuery,你可以订阅所有需要保持同步的 `LCQuery`。订阅成功后,一旦有符合 `LCQuery` 的 `LCObject` 发生变化,云端就会主动、实时地将信息通知到客户端。 - -LiveQuery 使用 WebSocket 在客户端和云端之间建立连接。WebSocket 的处理会比较复杂,而我们将其封装成了一个简单的 API 供你直接使用,无需关注背后的原理。 - -### 启用 LiveQuery - -进入 ** > 服务设置**,在 **安全设置** 里面勾选 **启用 LiveQuery** 即可。 - -如果没有集成 `Realtime` 模块,需先集成 `Realtime` 模块,pod 添加示例如下: - -```ruby -pod 'LeanCloudObjc/Realtime' -``` - -可以在 [SDK 安装与初始化](#sdk-安装与初始化) 中找到完整设置方法。 - -之后在相关头文件中导入 `Realtime` 模块,示例如下: - -```objc -#import -``` - -### Demo - -下面是在使用了 LiveQuery 的网页应用和手机应用中分别操作,数据保持同步的效果: - - - -使用我们的「LeanTodo」微信小程序和网页应用,可以实际体验以上视频所演示的效果,步骤如下: - -1. 微信扫码,添加小程序「LeanTodo」; - - ![LeanTodo mini program](/img/leantodo-weapp-qr.jpg) - -2. 进入小程序,点击首页左下角 **设置** > **账户设置**,输入便于记忆的用户名和密码; - -3. 使用浏览器访问 ,输入刚刚在小程序中更新好的账户信息,点击 **Login**; - -4. 随意添加更改数据,查看两端的同步状态。 - -注意按以上顺序操作。在网页应用中使用 **Signup** 注册的账户无法与小程序创建的账户相关联,所以如果颠倒以上操作顺序,则无法观测到数据同步效果。 - -[LiveQuery 公开课](http://www.bilibili.com/video/av11291992/) 涵盖了许多开发者关心的问题和解答。 - -### 构建订阅 - -首先创建一个普通的 `LCQuery` 对象,添加查询条件(如有),然后进行订阅操作: - -```objc -LCQuery *query = [LCQuery queryWithClassName:@"Todo"]; -self.liveQuery = [[LCLiveQuery alloc] initWithQuery:query]; -self.liveQuery.delegate = self; -[self.liveQuery subscribeWithCallback:^(BOOL succeeded, NSError * _Nonnull error) { - // 订阅成功 -}]; -``` - -LiveQuery 不支持内嵌查询,也不支持返回指定属性。 - -订阅成功后,就可以接收到和 `LCObject` 相关的更新了。假如在另一个客户端上创建了一个 `Todo` 对象,对象的 `title` 设为 `更新作品集`,那么下面的代码可以获取到这个新的 `Todo`: - -```objc -LCQuery *query = [LCQuery queryWithClassName:@"Todo"]; -self.liveQuery = [[LCLiveQuery alloc] initWithQuery:query]; -self.liveQuery.delegate = self; -[self.liveQuery subscribeWithCallback:^(BOOL succeeded, NSError * _Nonnull error) { - // 订阅成功 -}]; -- (void)liveQuery:(LCLiveQuery *)liveQuery objectDidCreate:(id)object { - if (liveQuery == self.liveQuery) { - NSLog(@"%@", object[@"title"]); // 更新作品集 - } -} -``` - -此时如果有人把 `Todo` 的 `content` 改为 `把我最近画的插画放上去`,那么下面的代码可以获取到本次更新: - -```objc -- (void)liveQuery:(LCLiveQuery *)liveQuery objectDidUpdate:(id)updatedTodo updatedKeys:(NSArray *)updatedKeys { - NSLog(@"%@", updatedTodo[@"content"]); // 把我最近画的插画放上去 -} -``` - -### 事件处理 - -订阅成功后,可以选择监听如下几种数据变化: - -- `create` -- `update` -- `enter` -- `leave` -- `delete` - -#### `create` 事件 - -当有新的满足 `LCQuery` 查询条件的 `LCObject` 被创建时,`create` 事件会被触发。下面的 `object` 就是新建的 `LCObject`: - -```objc -- (void)liveQuery:(LCLiveQuery *)liveQuery objectDidCreate:(id)object { - if (liveQuery == self.liveQuery) { - NSLog(@"对象被创建。"); - } -} -``` - -#### `update` 事件 - -当有满足 `LCQuery` 查询条件的 `LCObject` 被更新时,`update` 事件会被触发。下面的 `object` 就是有更新的 `LCObject`: - -```objc -- (void)liveQuery:(LCLiveQuery *)liveQuery objectDidUpdate:(id)object updatedKeys:(NSArray *)updatedKeys { - if (liveQuery == self.liveQuery) { - NSLog(@"对象被更新。"); - } -} -``` - -#### `enter` 事件 - -当一个已存在的、原本不符合 `LCQuery` 查询条件的 `LCObject` 发生更新,且更新后符合查询条件,`enter` 事件会被触发。下面的 `object` 就是进入 `LCQuery` 的 `LCObject`,其内容为该对象最新的值: - -```objc -- (void)liveQuery:(LCLiveQuery *)liveQuery objectDidEnter:(id)object updatedKeys:(nonnull NSArray *)updatedKeys { - if (liveQuery == self.liveQuery) { - NSLog(@"对象进入。"); - } -} -``` - -注意区分 `create` 和 `enter` 的不同行为。如果一个对象已经存在,在更新之前不符合查询条件,而在更新之后符合查询条件,那么 `enter` 事件会被触发。如果一个对象原本不存在,后来被构建了出来,那么 `create` 事件会被触发。 - -#### `leave` 事件 - -当一个已存在的、原本符合 `LCQuery` 查询条件的 `LCObject` 发生更新,且更新后不符合查询条件,`leave` 事件会被触发。下面的 `object` 就是离开 `LCQuery` 的 `LCObject`,其内容为该对象最新的值: - -```objc -- (void)liveQuery:(LCLiveQuery *)liveQuery objectDidLeave:(id)object updatedKeys:(nonnull NSArray *)updatedKeys { - if (liveQuery == self.liveQuery) { - NSLog(@"对象离开。"); - } -} -``` - -#### `delete` 事件 - -当一个已存在的、原本符合 `LCQuery` 查询条件的 `LCObject` 被删除,`delete` 事件会被触发。下面的 `object` 就是被删除的 `LCObject` 的 `objectId`: - -```objc -- (void)liveQuery:(LCLiveQuery *)liveQuery objectDidDelete:(id)object { - if (liveQuery == self.liveQuery) { - NSLog(@"对象被删除。"); - } -} -``` - -### 取消订阅 - -如果不再需要接收有关 `LCQuery` 的更新,可以取消订阅。 - -```objc -[liveQuery unsubscribeWithCallback:^(BOOL succeeded, NSError * _Nonnull error) { - if (succeeded) { - // 成功取消订阅 - } else { - // 错误处理 - } -}]; -``` - -### 断开连接 - -断开连接有几种情况: - -1. 网络异常或者网络切换,非预期性断开。 -2. 退出应用、关机或者打开飞行模式等,用户在应用外的操作导致断开。 - -如上几种情况开发者无需做额外的操作,只要切回应用,SDK 会自动重新订阅,数据变更会继续推送到客户端。 - -而另外一种极端情况——**当用户在移动端使用手机的进程管理工具,杀死了进程或者直接关闭了网页的情况下**,SDK 无法自动重新订阅,此时需要开发者根据实际情况实现重新订阅。 - -### LiveQuery 的注意事项 - -因为 LiveQuery 的实时性,很多用户会陷入一个误区,试着用 LiveQuery 来实现一个简单的聊天功能。 -我们不建议这样做,因为使用 LiveQuery 构建聊天服务会承担额外的存储成本,产生的费用会增加,后期维护的难度非常大(聊天记录、对话维护之类的代码会很混乱),并且云服务已经提供了即时通讯的服务。 -LiveQuery 的核心还是提供一个针对查询的推拉结合的用法,脱离设计初衷容易造成前端的模块混乱。 - - ## 文件