├── .gitignore
├── README.md
└── lc_realtime
├── .gitignore
├── .gradle
├── 5.2.1
│ ├── fileChanges
│ │ └── last-build.bin
│ ├── fileHashes
│ │ └── fileHashes.lock
│ └── gc.properties
├── buildOutputCleanup
│ ├── buildOutputCleanup.lock
│ └── cache.properties
└── vcs-1
│ └── gc.properties
├── .metadata
├── README.md
├── android
├── .gitignore
├── app
│ ├── agconnect-services.json
│ ├── build.gradle
│ ├── libs
│ │ ├── MiPush_SDK_Client_3_7_5.jar
│ │ ├── oppo-mcssdk-2.0.2.jar
│ │ └── vivo_pushsdk-v2.9.0.0.aar
│ └── src
│ │ ├── debug
│ │ └── AndroidManifest.xml
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── example
│ │ │ │ └── lcrealtime
│ │ │ │ ├── MainActivity.java
│ │ │ │ └── MyApplication.java
│ │ └── res
│ │ │ ├── drawable
│ │ │ └── launch_background.xml
│ │ │ ├── mipmap-hdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-mdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ └── ic_launcher.png
│ │ │ └── values
│ │ │ └── styles.xml
│ │ └── profile
│ │ └── AndroidManifest.xml
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
├── settings.gradle
└── test.keystore
├── assets
└── download_fail.png
├── ios
├── .gitignore
├── Flutter
│ ├── AppFrameworkInfo.plist
│ ├── Debug.xcconfig
│ └── Release.xcconfig
├── Podfile
├── Podfile.lock
├── Runner.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ └── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── Runner.xcscheme
├── Runner.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ ├── IDEWorkspaceChecks.plist
│ │ └── WorkspaceSettings.xcsettings
└── Runner
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ ├── Contents.json
│ │ ├── Icon-App-1024x1024@1x.png
│ │ ├── Icon-App-20x20@1x.png
│ │ ├── Icon-App-20x20@2x.png
│ │ ├── Icon-App-20x20@3x.png
│ │ ├── Icon-App-29x29@1x.png
│ │ ├── Icon-App-29x29@2x.png
│ │ ├── Icon-App-29x29@3x.png
│ │ ├── Icon-App-40x40@1x.png
│ │ ├── Icon-App-40x40@2x.png
│ │ ├── Icon-App-40x40@3x.png
│ │ ├── Icon-App-60x60@2x.png
│ │ ├── Icon-App-60x60@3x.png
│ │ ├── Icon-App-76x76@1x.png
│ │ ├── Icon-App-76x76@2x.png
│ │ └── Icon-App-83.5x83.5@2x.png
│ └── LaunchImage.imageset
│ │ ├── Contents.json
│ │ ├── LaunchImage.png
│ │ ├── LaunchImage@2x.png
│ │ ├── LaunchImage@3x.png
│ │ └── README.md
│ ├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
│ ├── Info.plist
│ ├── Runner-Bridging-Header.h
│ ├── RunnerDebug.entitlements
│ └── RunnerRelease.entitlements
├── lib
├── Common
│ └── Global.dart
├── Models
│ └── CurrentClient.dart
├── Routes
│ ├── ContactsPage.dart
│ ├── ConversationDetailPage.dart
│ ├── ConversationListPage.dart
│ ├── HomeBottomBar.dart
│ ├── LoginPage.dart
│ ├── SelectChatMembers.dart
│ └── UserProtocol.dart
├── States
│ ├── ChangeNotifier.dart
│ ├── ChangeNotifierProvider.dart
│ ├── Consumer.dart
│ ├── ConversationModel.dart
│ ├── GlobalEvent.dart
│ └── InheritedWidget.dart
├── Widgets
│ ├── InputMessageView.dart
│ ├── MessageList.dart
│ └── TextWidget.dart
└── main.dart
├── pubspec.lock
├── pubspec.yaml
└── test
└── widget_test.dart
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 |
12 | # IntelliJ related
13 | *.iml
14 | *.ipr
15 | *.iws
16 | .idea/
17 |
18 | # The .vscode folder contains launch configuration and tasks you configure in
19 | # VS Code which you may wish to be included in version control, so this line
20 | # is commented out by default.
21 | #.vscode/
22 |
23 | # Flutter/Dart/Pub related
24 | **/doc/api/
25 | **/ios/Flutter/.last_build_id
26 | .dart_tool/
27 | .flutter-plugins
28 | .flutter-plugins-dependencies
29 | .packages
30 | .pub-cache/
31 | .pub/
32 | /build/
33 |
34 | # Web related
35 | lib/generated_plugin_registrant.dart
36 |
37 | # Symbolication related
38 | app.*.symbols
39 |
40 | # Obfuscation related
41 | app.*.map.json
42 |
43 | # Android Studio will place build artifacts here
44 | /android/app/debug
45 | /android/app/profile
46 | /android/app/release
47 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Flutter 新手上路,UI 还有一些问题正在解决中,欢迎小伙伴批评指正 :)
2 | * [apk 体验链接](https://flutter-rtm-files.lncld.net/fWtxzeC8GzvFGTB3r0G7gBl1rvnbjyI9/app-release.apk)
3 | ## 应用简介
4 |
5 | 本应用是一款社交聊天的应用,实现了基本的聊天需求。实现这款应用一方面是为了了解与学习 Flutter,另一方面趁此机会熟悉 LeanCloud 即时通信 Flutter SDK 的使用。
6 |
7 | 应用还在持续完善中,现已经支持如下功能:
8 |
9 | - 登录、登出
10 | - 发起单聊
11 | - 发起群聊
12 | - 支持文字消息、语音消息、图片消息
13 | - 支持展示未读消息数
14 | - 支持展示会话成员
15 | - 支持修改会话名称
16 | - 支持离线消息推送
17 | - 投诉举报不良信息
18 | - 把某用户加入黑名单
19 |
20 | ### 页面截图
21 |
22 |
23 |

24 |

25 |
26 |
27 |
28 |
29 | ## 开发环境搭建
30 |
31 | 第一步:Flutter 安装和环境搭建直接查看:[ Flutter 文档](https://flutter.dev/docs/get-started/install)。
32 | 第二步:登录 [LeanCloud 控制台](https://leancloud.cn/dashboard/login.html#/signin),创建 LeanCloud 应用。
33 |
34 | - 在控制台 > 应用 > 设置 >域名绑定页面绑定 **API 访问域名**。暂时没有域名可以略过这一步,LeanCloud 也提供了短期有效的免费体验域名;或者注册[ LeanCloud 国际版](https://console.leancloud.app/login.html#/signin),国际版不要求绑定域名。
35 | - 在控制台 > 应用 > 设置 > 应用 Keys 页面记录 AppID、AppKey 与服务器地址备用,这里的服务器地址就是 REST API 服务器地址。如果未绑定域名,控制台相同的位置可以获取到免费的共享域名。
36 |
37 | ## APP 初始化设置
38 |
39 | 在 pubspec.yaml 中,将 LeanCloud Flutter SDK 添加到依赖项列表:
40 |
41 | ```
42 | dependencies:
43 | leancloud_official_plugin: ^1.0.0 //即时通信插件
44 | leancloud_storage: ^0.7.7 //数据存储 SDK
45 | ```
46 |
47 | 然后运行 flutter pub get 安装 SDK。
48 |
49 | 因为 leancloud_official_plugin 是基于 [Swift SDK](https://github.com/leancloud/swift-sdk) 以及 [Java Unified SDK](https://github.com/leancloud/java-unified-sdk) 开发,所以还要安装后面两个 SDK,这样应用才能分别在 iOS 和 Android 设备运行。
50 |
51 | 需要通过 CocoaPods 安装 Swift SDK,这一步和安装 iOS 其他第三方库是一样的,在应用的 ios 目录下执行 pod update 即可。
52 |
53 | ```
54 | $ cd ios/
55 | $ pod update # 或者 $ pod install --repo-update
56 | ```
57 |
58 | 同样的,需要配置 Gradle 来安装 Java Unified SDK,打开工程目录 android/app/build.gradle,添加如下依赖,用 Android Studio 打开工程下的 android 目录,同步更新 Gradle 即可。
59 |
60 | ```
61 | dependencies {
62 | implementation 'cn.leancloud:storage-android:8.1.4'
63 | implementation 'cn.leancloud:realtime-android:8.1.4'
64 | implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
65 | }
66 | ```
67 |
68 | > 小 tips: 安装 SDK 期间遇到任何困难都可在 [LeanCloud 社区](https://forum.leancloud.cn/latest) 发帖求助。
69 |
70 | SDK 安装成功以后,需要分别 [初始化 iOS 和 Android 平台](https://leancloud.cn/docs/sdk_setup-flutter.html#hash662673194)。
71 |
72 | ## 用户系统
73 |
74 | Demo 里面并没有内置用户系统,可以选择联系人列表中的用户名来登录聊天系统。LeanCloud 即时通信服务端中只需要传入一个唯一标识字符串既可以表示一个「用户」,对应唯一的 Client, 在应用内唯一标识自己的 ID(clientId)。
75 |
76 | 在自己的项目中,如果已经有独立的用户系统也很方便维护。
77 | 或者使用 LeanStorage 提供的[用户系统](https://leancloud.cn/docs/leanstorage_guide-java.html#hash954895)。
78 |
79 | ## 会话列表
80 |
81 | 会话列表要展示当前用户所参与的会话,会话名称、会话的成员,会话的最后一条消息。还需要展示未读消息数目。
82 |
83 | 会话列表对应 Conversation 表,查询当前用户的全部会话只需要下面两行代码:
84 |
85 | ```
86 | ConversationQuery query = client.conversationQuery();
87 | await query.find();
88 | ```
89 |
90 | 按照会话的更新时间排序:
91 |
92 | ```
93 | query.orderByDescending('updatedAt');
94 | ```
95 |
96 | 为了展示会话的最新一条消息,查询的时候要额外加上这行代码:
97 |
98 | ```
99 | //让查询结果附带一条最新消息
100 | query.includeLastMessage = true;
101 | ```
102 |
103 | 这样会话页面的后端数据就搞定了。下面看一下如何显示数据。
104 |
105 | 会话查询成功返回的数据格式是 Conversation 类型的 List。
106 |
107 | - conversation.name 即会话的名称
108 | - conversation.members 即会话成员
109 | - conversation.lastMessage 就是当前会话的最新一条消息了。
110 |
111 | ### 未读消息数的处理
112 |
113 | 如果要在 Android 设备上运行,需要在初始化 Java SDK 的时候加上下面这行代码,表示开启未读消息数通知:
114 |
115 | ```
116 | AVIMOptions.getGlobalOptions().setUnreadNotificationEnabled(true);
117 | ```
118 |
119 | swift SDK 是默认支持,无需额外设置。
120 |
121 | 可以监听 onUnreadMessageCountUpdated 时间获取未读消息数通知:
122 |
123 | ```
124 | client.onUnreadMessageCountUpdated = ({
125 | Client client,
126 | Conversation conversation,
127 | }) {
128 | // conversation.unreadMessageCount 即该 conversation 的未读消息数量
129 | };
130 | ```
131 |
132 | 注意要在以下两处清除未读消息数:
133 |
134 | - 在对话列表点击某对话进入到对话页面时
135 | - 用户正在某个对话页面聊天,并在这个对话中收到了消息时
136 |
137 | ## 会话详情页面
138 |
139 | ### 上拉加载更多历史消息
140 |
141 | 查询聊天记录的时候,先查最近的 10 条消息,然后以第一页的最早的消息作为开始,继续向前拉取消息:
142 |
143 | ```
144 | List messages;
145 | try {
146 | //第一次查询成功
147 | messages = await conversation.queryMessage(
148 | limit: 10,
149 | );
150 | } catch (e) {
151 | print(e);
152 | }
153 |
154 | try {
155 | // 返回的消息一定是时间增序排列,也就是最早的消息一定是第一个
156 | Message oldMessage = messages.first;
157 | // 以第一页的最早的消息作为开始,继续向前拉取消息
158 | List messages2 = await conversation.queryMessage(
159 | startTimestamp: oldMessage.sentTimestamp,
160 | startMessageID: oldMessage.id,
161 | startClosed: true,
162 | limit: 10,
163 | );
164 | } catch (e) {
165 | print(e);
166 | }
167 | ```
168 |
169 | ### 修改会话名
170 |
171 | 对话的名称是会话表 Conversation 默认的属性,更新会话名称只需要执行:
172 |
173 | ```
174 | await conversation.updateInfo(attributes: {
175 | 'name': 'New Name',
176 | });
177 | ```
178 |
179 | ### 图片、语音消息
180 |
181 | LeanCloud 即时通信 SDK 提供了下面几种默认的消息类型,Demo 中只用到了文本消息,图像消息和语音消息。
182 |
183 | - TextMessage 文本消息
184 | - ImageMessage 图像消息
185 | - AudioMessage 音频消息
186 | - VideoMessage 视频消息
187 | - FileMessage 普通文件消息(.txt/.doc/.md 等各种)
188 | - LocationMessage 地理位置消息
189 |
190 | **注意,图片与语音消息需要先保存成 LCFile,然后再调用发消息接口发消息。**
191 |
192 | 比如发送音频消息。第一步先保存音频文件为 LCFile:
193 |
194 | ```
195 | LCFile file = await LCFile.fromPath('message.wav', path);
196 | await file.save();
197 | ```
198 |
199 | 第二步,再发消息:
200 |
201 | ```
202 | //发送消息
203 | AudioMessage audioMessage = AudioMessage.from(
204 | binaryData: file.data,
205 | format: 'wav',
206 | );
207 | await this.widget.conversation.send(message: audioMessage);
208 | ```
209 |
210 | 还要注意 iOS 设备发送图片消息注意打开相册和相机权限,语音消息需要麦克风权限:
211 |
212 | ```
213 | NSMicrophoneUsageDescription
214 | 录音功能需要访问麦克风,如果不允许,你将无法在聊天过程中发送语音消息。
215 |
216 | NSCameraUsageDescription
217 | 发送图片功能需要访问您的相机。如果不允许,你将无法在聊天过程中发送图片消息。
218 |
219 | NSPhotoLibraryUsageDescription
220 | 发送图片功能需要访问您的相册。如果不允许,你将无法在聊天过程中发送相册中的图片。
221 | ```
222 |
223 | ## 离线推送通知
224 |
225 | 当用户下线以后,收到消息的时候,往往希望能有推送提醒。最简单的一种推送设置就是在 LeanCloud **控制台 > 消息 > 即时通讯 > 设置 > 离线推送设置** 页面,填入:
226 |
227 | ```
228 | { "alert": "您有新的消息", "badge": "Increment" }
229 | ```
230 |
231 | 这样 iOS 设备有离线消息的时候会收到提醒。这里 badge 参数为 iOS 设备专用,用于增加应用 badge 上的数字计数。
232 |
233 | > 如果想在 Android 设备上实现离线推送,要增加一步接入[ Android 混合推送](https://leancloud.cn/docs/android_mixpush_guide.html)。
234 |
235 | 当然在实际项目中,离线消息的提醒往往会要求更加具体,比如推送中要包括消息的内容或者消息类型等。LeanCloud 也提供了其他几种定制离线推送的方法,感兴趣可以自行查阅[文档](https://leancloud.cn/docs/realtime-guide-intermediate.html#hash-485620600)。
236 |
237 | 还要注意,iOS 推送一定要正确配置 [配置 APNs 推送证书](https://leancloud.cn/docs/ios_push_cert.html),并打开 Xcode 的推送开关:
238 |
239 |
240 |
241 |
242 | AppDelegate.swift 中开启推送,要这样设置:
243 |
244 | ```
245 | import Flutter
246 | import LeanCloud
247 | import UserNotifications
248 |
249 | @UIApplicationMain
250 | @objc class AppDelegate: FlutterAppDelegate {
251 | override func application(
252 | _ application: UIApplication,
253 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
254 | ) -> Bool {
255 | do {
256 | LCApplication.logLevel = .all
257 | try LCApplication.default.set(
258 | id: "你的APPID",
259 | key: "你的 APPKey",
260 | serverURL: "服务器地址")
261 | GeneratedPluginRegistrant.register(with: self)
262 | /*
263 | register APNs to access token, like this:
264 | */
265 | UNUserNotificationCenter.current().getNotificationSettings { (settings) in
266 | switch settings.authorizationStatus {
267 | case .authorized:
268 | DispatchQueue.main.async {
269 | UIApplication.shared.registerForRemoteNotifications()
270 | }
271 | case .notDetermined:
272 | UNUserNotificationCenter.current().requestAuthorization(options: [.badge, .alert, .sound]) { (granted, error) in
273 | if granted {
274 | DispatchQueue.main.async {
275 | UIApplication.shared.registerForRemoteNotifications()
276 | }
277 | }
278 | }
279 | default:
280 | break
281 | }
282 | _ = LCApplication.default.currentInstallation
283 | }
284 | return super.application(application, didFinishLaunchingWithOptions: launchOptions)
285 | } catch {
286 | fatalError("\(error)")
287 | }
288 | }
289 |
290 | override func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
291 | /*
292 | set APNs deviceToken and Team ID.
293 | */
294 | LCApplication.default.currentInstallation.set(
295 | deviceToken: deviceToken,
296 | apnsTeamId: "你的 TeamId")
297 | /*
298 | save to LeanCloud.
299 | */
300 | LCApplication.default.currentInstallation.save { (result) in
301 | switch result {
302 | case .success:
303 | break
304 | case .failure(error: let error):
305 | print(error)
306 | }
307 | }
308 | }
309 | override func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
310 | //如果注册推送失败,可以检查 error 信息
311 | print(error)
312 | }
313 | }
314 | ```
315 |
316 | ## 投诉举报、黑名单
317 |
318 | 在 APP Store 审核过程中,因为用户可以随意发送消息,被要求对用户生成的内容要有适当的预防措施。
319 |
320 | 要求提供下面这两条内容:
321 |
322 | - A mechanism for users to flag objectionable content
323 |
324 | 用户标记不良信息的机制,就是举报功能。
325 |
326 | - A mechanism for users to block abusive users
327 |
328 | 用户阻止滥用用户的机制,实际就是黑名单。
329 |
330 | ### 实现举报功能
331 |
332 | 我的解决办法是在消息处长按弹出举报窗口。
333 |
334 |
335 |
336 | 使用 LeanCloud 存储服务,新建一张 Report 表用于记录举报信息:
337 |
338 | ```
339 | //保存一条举报信息
340 | LCObject report = LCObject('Report');
341 | report['clientID'] = Global.clientID; //举报人
342 | report['messageID'] = messageID; //消息 ID
343 | report['conversationID'] = this.widget.conversation.id; //会话 ID
344 | report['content'] = _selectedReportList.toString(); //举报内容
345 | await report.save(); //保存举报信息
346 | ```
347 |
348 | 可以在控制台查看举报内容:
349 |
350 | 
351 |
352 | ### 实现黑名单功能
353 |
354 |
355 |
356 | 我的解决办法是,在联系人列表处单击联系人弹框提示是否加入黑名单。
357 |
358 | 黑名单实现思路是新建一张 BlackList 表,来保存每个用户的黑名单列表,使用 [LeanCloud 云函数](https://leancloud.cn/docs/realtime-guide-systemconv.html#hash1748033991) 实现屏蔽消息。在 [_messageReceived](https://leancloud.cn/docs/realtime-guide-systemconv.html#hash-1573260517) 这个 Hook 函数下(这个 hook 发生在消息到达 LeanCloud 云端之后),先查此条消息的发件人与收件人是否在黑名单列表,如果在黑名单列表就删除其中要求屏蔽的收件人,返回新的收件人列表。
359 |
360 | 实现起来也比较简单,把下面这个云函数粘贴在 LeanCloud 控制台 > 云引擎 >云函数在线编辑框中即可。
361 |
362 | 
363 |
364 | > 步骤
365 | >
366 | > 先点击「创建函数」,然后选择 _messageReceived 类型,粘贴下面的代码,最后点击「部署」按钮。
367 |
368 | 等待部署完成,黑名单功能就已经实现成功,将不再收到加入黑名单用户的全部消息。
369 |
370 | ```
371 | //下面这个函数粘贴在 LeanCloud 控制台
372 |
373 | AV.Cloud.define('_messageReceived', async function(request) {
374 | let fromPeer = request.params.fromPeer;
375 | let toPeersNew = request.params.toPeers;
376 |
377 | var query = new AV.Query('BlackList');
378 | query.equalTo('blackedList', fromPeer);
379 | query.containedIn('clientID', toPeersNew);
380 | return query.find().then((results) => {
381 | if (results.length > 0) {
382 | var clientID = results[0].get('clientID');
383 | var index = toPeersNew.indexOf(clientID);
384 | if (index > -1) {
385 | toPeersNew.splice(index, 1);
386 | }
387 | return {
388 | toPeers: toPeersNew
389 | }
390 | }
391 | return {
392 | }
393 | });
394 | })
395 | ```
396 |
397 | ## APP 安装(因开发者账号调整,暂不可用)
398 |
399 | [APP Store 下载链接](https://apps.apple.com/cn/app/leanmessage/id1529417244)
400 |
401 | ## 文档
402 |
403 | - [LeanCloud 即时通信插件链接](https://pub.dev/packages/leancloud_official_plugin#leancloud_official_plugin)
404 | - [LeanCloud 即时通信开发文档](https://leancloud.cn/docs/#即时通讯)
405 | - [Flutter 文档](https://flutter.dev/docs)
406 |
--------------------------------------------------------------------------------
/lc_realtime/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 |
12 | # IntelliJ related
13 | *.iml
14 | *.ipr
15 | *.iws
16 | .idea/
17 |
18 | # The .vscode folder contains launch configuration and tasks you configure in
19 | # VS Code which you may wish to be included in version control, so this line
20 | # is commented out by default.
21 | #.vscode/
22 |
23 | # Flutter/Dart/Pub related
24 | **/doc/api/
25 | **/ios/Flutter/.last_build_id
26 | .dart_tool/
27 | .flutter-plugins
28 | .flutter-plugins-dependencies
29 | .packages
30 | .pub-cache/
31 | .pub/
32 | /build/
33 |
34 | # Web related
35 | lib/generated_plugin_registrant.dart
36 |
37 | # Symbolication related
38 | app.*.symbols
39 |
40 | # Obfuscation related
41 | app.*.map.json
42 |
43 | # Android Studio will place build artifacts here
44 | /android/app/debug
45 | /android/app/profile
46 | /android/app/release
47 |
--------------------------------------------------------------------------------
/lc_realtime/.gradle/5.2.1/fileChanges/last-build.bin:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/lc_realtime/.gradle/5.2.1/fileHashes/fileHashes.lock:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SXiaoXu/FlutterRealtimeDemo/d0e9998e1d168bb7d68cd9a06e7e66c182e036cd/lc_realtime/.gradle/5.2.1/fileHashes/fileHashes.lock
--------------------------------------------------------------------------------
/lc_realtime/.gradle/5.2.1/gc.properties:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SXiaoXu/FlutterRealtimeDemo/d0e9998e1d168bb7d68cd9a06e7e66c182e036cd/lc_realtime/.gradle/5.2.1/gc.properties
--------------------------------------------------------------------------------
/lc_realtime/.gradle/buildOutputCleanup/buildOutputCleanup.lock:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SXiaoXu/FlutterRealtimeDemo/d0e9998e1d168bb7d68cd9a06e7e66c182e036cd/lc_realtime/.gradle/buildOutputCleanup/buildOutputCleanup.lock
--------------------------------------------------------------------------------
/lc_realtime/.gradle/buildOutputCleanup/cache.properties:
--------------------------------------------------------------------------------
1 | #Fri May 08 12:27:13 CST 2020
2 | gradle.version=5.2.1
3 |
--------------------------------------------------------------------------------
/lc_realtime/.gradle/vcs-1/gc.properties:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SXiaoXu/FlutterRealtimeDemo/d0e9998e1d168bb7d68cd9a06e7e66c182e036cd/lc_realtime/.gradle/vcs-1/gc.properties
--------------------------------------------------------------------------------
/lc_realtime/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled and should not be manually edited.
5 |
6 | version:
7 | revision: 27321ebbad34b0a3fafe99fac037102196d655ff
8 | channel: stable
9 |
10 | project_type: app
11 |
--------------------------------------------------------------------------------
/lc_realtime/README.md:
--------------------------------------------------------------------------------
1 | # lcrealtime
2 |
3 | A new Flutter application.
4 |
5 | ## Getting Started
6 |
7 | This project is a starting point for a Flutter application.
8 |
9 | A few resources to get you started if this is your first Flutter project:
10 |
11 | - [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab)
12 | - [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook)
13 |
14 | For help getting started with Flutter, view our
15 | [online documentation](https://flutter.dev/docs), which offers tutorials,
16 | samples, guidance on mobile development, and a full API reference.
17 |
--------------------------------------------------------------------------------
/lc_realtime/android/.gitignore:
--------------------------------------------------------------------------------
1 | gradle-wrapper.jar
2 | /.gradle
3 | /captures/
4 | /gradlew
5 | /gradlew.bat
6 | /local.properties
7 | GeneratedPluginRegistrant.java
8 |
--------------------------------------------------------------------------------
/lc_realtime/android/app/agconnect-services.json:
--------------------------------------------------------------------------------
1 | {
2 | "agcgw":{
3 | "backurl":"connect-drcn.dbankcloud.cn",
4 | "url":"connect-drcn.hispace.hicloud.com"
5 | },
6 | "client":{
7 | "cp_id":"890086000102298554",
8 | "product_id":"9105371292390931866",
9 | "client_id":"315681308267250688",
10 | "client_secret":"56E8F24C182F4C4920B300833238FA3D68E474A6FF288E4B016AA9D779EBEE7F",
11 | "app_id":"101912147",
12 | "package_name":"cn.leancloud.demo.mixpush",
13 | "api_key":"CV6QAq2ligdk9gSk//NnHzViDb8puYQpks7kGgX+7sOQC8P1J5tObmlzZaf72l0QXoS8BDSEL/5iolU645u/Qsr8SSpR"
14 | },
15 | "service":{
16 | "analytics":{
17 | "collector_url":"datacollector-drcn.dt.hicloud.com,datacollector-drcn.dt.dbankcloud.cn",
18 | "resource_id":"p1",
19 | "channel_id":""
20 | },
21 | "cloudstorage":{
22 | "storage_url":"https://agc-storage-drcn.platform.dbankcloud.cn"
23 | },
24 | "ml":{
25 | "mlservice_url":"ml-api-drcn.ai.dbankcloud.com,ml-api-drcn.ai.dbankcloud.cn"
26 | }
27 | },
28 | "region":"CN",
29 | "configuration_version":"1.0"
30 | }
--------------------------------------------------------------------------------
/lc_realtime/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | def localProperties = new Properties()
2 | def localPropertiesFile = rootProject.file('local.properties')
3 | if (localPropertiesFile.exists()) {
4 | localPropertiesFile.withReader('UTF-8') { reader ->
5 | localProperties.load(reader)
6 | }
7 | }
8 |
9 | def flutterRoot = localProperties.getProperty('flutter.sdk')
10 | if (flutterRoot == null) {
11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
12 | }
13 |
14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
15 | if (flutterVersionCode == null) {
16 | flutterVersionCode = '1'
17 | }
18 |
19 | def flutterVersionName = localProperties.getProperty('flutter.versionName')
20 | if (flutterVersionName == null) {
21 | flutterVersionName = '1.0'
22 | }
23 | apply plugin: 'com.huawei.agconnect'
24 | apply plugin: 'com.android.application'
25 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
26 |
27 |
28 | android {
29 |
30 | // signingConfigs {
31 | // config {
32 | // keyPassword '123456'
33 | // keyAlias 'testalias'
34 | // storeFile file('/Users/vivian/Documents/LeanCloud/Flutter_WorkPlace/FlutterRealtimeDemo/lc_realtime/android/test.keystore')
35 | // storePassword '123456'
36 | // }
37 | // }
38 | //配置签名
39 | compileSdkVersion 28
40 |
41 | lintOptions {
42 | disable 'InvalidPackage'
43 | }
44 |
45 | defaultConfig {
46 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
47 | applicationId "com.example.lcrealtime"
48 | minSdkVersion 23
49 | targetSdkVersion 28
50 | multiDexEnabled true
51 | versionCode flutterVersionCode.toInteger()
52 | versionName flutterVersionName
53 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
54 | }
55 |
56 | buildTypes {
57 | // debug {
58 | // signingConfig signingConfigs.config
59 | // }
60 | // release {
61 | // signingConfig signingConfigs.config
62 | // minifyEnabled false
63 | // proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
64 | // }
65 | }
66 | }
67 |
68 | flutter {
69 | source '../..'
70 | }
71 |
72 | dependencies {
73 | implementation fileTree(dir: 'libs', include: ['*.jar'])
74 | // implementation files("libs/vivo_pushsdk-v2.9.0.0.aar")
75 | // implementation 'cn.leancloud:mixpush-oppo:6.5.12'
76 |
77 | testImplementation 'junit:junit:4.12'
78 | androidTestImplementation 'androidx.test:runner:1.1.1'
79 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
80 |
81 | //使用存储服务
82 | implementation 'cn.leancloud:storage-android:8.1.4'
83 | //使用即时通信
84 | implementation 'cn.leancloud:realtime-android:8.1.4'
85 | implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
86 | //混合推送需要的包
87 | // implementation 'cn.leancloud:mixpush-android:6.5.12'
88 | //华为推送
89 | // implementation 'com.huawei.hms:push:4.0.2.300'
90 | // 魅族推送需要的包
91 | // implementation 'com.meizu.flyme.internet:push-internal:3.6.+@aar'
92 | // implementation files("libs/vivo_pushsdk-v2.9.0.0.aar")
93 | // implementation 'cn.leancloud:mixpush-oppo:6.5.12'
94 | }
95 |
--------------------------------------------------------------------------------
/lc_realtime/android/app/libs/MiPush_SDK_Client_3_7_5.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SXiaoXu/FlutterRealtimeDemo/d0e9998e1d168bb7d68cd9a06e7e66c182e036cd/lc_realtime/android/app/libs/MiPush_SDK_Client_3_7_5.jar
--------------------------------------------------------------------------------
/lc_realtime/android/app/libs/oppo-mcssdk-2.0.2.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SXiaoXu/FlutterRealtimeDemo/d0e9998e1d168bb7d68cd9a06e7e66c182e036cd/lc_realtime/android/app/libs/oppo-mcssdk-2.0.2.jar
--------------------------------------------------------------------------------
/lc_realtime/android/app/libs/vivo_pushsdk-v2.9.0.0.aar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SXiaoXu/FlutterRealtimeDemo/d0e9998e1d168bb7d68cd9a06e7e66c182e036cd/lc_realtime/android/app/libs/vivo_pushsdk-v2.9.0.0.aar
--------------------------------------------------------------------------------
/lc_realtime/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/lc_realtime/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
20 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
46 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/lc_realtime/android/app/src/main/java/com/example/lcrealtime/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.lcrealtime;
2 |
3 | import androidx.annotation.NonNull;
4 |
5 | import io.flutter.embedding.android.FlutterActivity;
6 | import io.flutter.embedding.engine.FlutterEngine;
7 | import io.flutter.plugins.GeneratedPluginRegistrant;
8 |
9 | public class MainActivity extends FlutterActivity {
10 | @Override
11 | public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
12 | // AVMixPushManager.connectHMS(this);
13 | GeneratedPluginRegistrant.registerWith(flutterEngine);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/lc_realtime/android/app/src/main/java/com/example/lcrealtime/MyApplication.java:
--------------------------------------------------------------------------------
1 | package com.example.lcrealtime;
2 | import cn.leancloud.LCLogger;
3 | import cn.leancloud.LeanCloud;
4 | import cn.leancloud.im.LCIMOptions;
5 | import io.flutter.app.FlutterApplication;
6 |
7 | public class MyApplication extends FlutterApplication{
8 | private static final String LC_App_Id = "1eUivazFXYwJvuGpPl2LE4uY-gzGzoHsz";
9 | private static final String LC_App_Key = "nLMIaQSwIsHfF206PnOFoYYa";
10 | private static final String LC_Server_Url = "https://1euivazf.lc-cn-n1-shared.com";
11 | // private static final String MEIZU_APP = "119851";
12 | // private static final String MEIZU_KEY = "73c48ba926fb40b898797b819030830d";
13 | //
14 | // private static final String MI_APPID = "2882303761517988199";
15 | // private static final String MI_APPKEY = "5571798886199";
16 | @Override
17 | public void onCreate() {
18 | super.onCreate();
19 |
20 | LCIMOptions.getGlobalOptions().setUnreadNotificationEnabled(true);
21 |
22 | LeanCloud.setLogLevel(LCLogger.Level.DEBUG);
23 | LeanCloud.initialize(this, LC_App_Id, LC_App_Key, LC_Server_Url);
24 |
25 | // //华为推送
26 | // LCMixPushManager.registerHMSPush(this);
27 | // //小米
28 | // LCMixPushManager.registerXiaomiPush(this , MI_APPID, MI_APPKEY);
29 | // //魅族
30 | // LCMixPushManager.registerFlymePush(this, MEIZU_APP, MEIZU_KEY);
31 |
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/lc_realtime/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/lc_realtime/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SXiaoXu/FlutterRealtimeDemo/d0e9998e1d168bb7d68cd9a06e7e66c182e036cd/lc_realtime/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/lc_realtime/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SXiaoXu/FlutterRealtimeDemo/d0e9998e1d168bb7d68cd9a06e7e66c182e036cd/lc_realtime/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/lc_realtime/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SXiaoXu/FlutterRealtimeDemo/d0e9998e1d168bb7d68cd9a06e7e66c182e036cd/lc_realtime/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/lc_realtime/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SXiaoXu/FlutterRealtimeDemo/d0e9998e1d168bb7d68cd9a06e7e66c182e036cd/lc_realtime/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/lc_realtime/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SXiaoXu/FlutterRealtimeDemo/d0e9998e1d168bb7d68cd9a06e7e66c182e036cd/lc_realtime/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/lc_realtime/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
--------------------------------------------------------------------------------
/lc_realtime/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/lc_realtime/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | google()
4 | jcenter()
5 | maven {url 'http://developer.huawei.com/repo/'}
6 | // mavenLocal()
7 | }
8 |
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:3.6.3'
11 | classpath 'com.huawei.agconnect:agcp:1.2.1.301'
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | google()
18 | jcenter()
19 | maven {url 'http://developer.huawei.com/repo/'}
20 | // mavenLocal()
21 | }
22 | }
23 |
24 | rootProject.buildDir = '../build'
25 | subprojects {
26 | project.buildDir = "${rootProject.buildDir}/${project.name}"
27 | }
28 | subprojects {
29 | project.evaluationDependsOn(':app')
30 | }
31 |
32 | task clean(type: Delete) {
33 | delete rootProject.buildDir
34 | }
35 |
--------------------------------------------------------------------------------
/lc_realtime/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 | #android.enableR8=true
3 | android.useAndroidX=true
4 | android.enableJetifier=true
5 |
--------------------------------------------------------------------------------
/lc_realtime/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri May 08 12:43:48 CST 2020
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
7 |
--------------------------------------------------------------------------------
/lc_realtime/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
4 |
5 | def plugins = new Properties()
6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
7 | if (pluginsFile.exists()) {
8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
9 | }
10 |
11 | plugins.each { name, path ->
12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
13 | include ":$name"
14 | project(":$name").projectDir = pluginDirectory
15 | }
16 |
--------------------------------------------------------------------------------
/lc_realtime/android/test.keystore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SXiaoXu/FlutterRealtimeDemo/d0e9998e1d168bb7d68cd9a06e7e66c182e036cd/lc_realtime/android/test.keystore
--------------------------------------------------------------------------------
/lc_realtime/assets/download_fail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SXiaoXu/FlutterRealtimeDemo/d0e9998e1d168bb7d68cd9a06e7e66c182e036cd/lc_realtime/assets/download_fail.png
--------------------------------------------------------------------------------
/lc_realtime/ios/.gitignore:
--------------------------------------------------------------------------------
1 | *.mode1v3
2 | *.mode2v3
3 | *.moved-aside
4 | *.pbxuser
5 | *.perspectivev3
6 | **/*sync/
7 | .sconsign.dblite
8 | .tags*
9 | **/.vagrant/
10 | **/DerivedData/
11 | Icon?
12 | **/Pods/
13 | **/.symlinks/
14 | profile
15 | xcuserdata
16 | **/.generated/
17 | Flutter/App.framework
18 | Flutter/Flutter.framework
19 | Flutter/Flutter.podspec
20 | Flutter/Generated.xcconfig
21 | Flutter/app.flx
22 | Flutter/app.zip
23 | Flutter/flutter_assets/
24 | Flutter/flutter_export_environment.sh
25 | ServiceDefinitions.json
26 | Runner/GeneratedPluginRegistrant.*
27 |
28 | # Exceptions to above rules.
29 | !default.mode1v3
30 | !default.mode2v3
31 | !default.pbxuser
32 | !default.perspectivev3
33 |
--------------------------------------------------------------------------------
/lc_realtime/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | App
9 | CFBundleIdentifier
10 | io.flutter.flutter.app
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | App
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | MinimumOSVersion
24 | 9.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/lc_realtime/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/lc_realtime/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/lc_realtime/ios/Podfile:
--------------------------------------------------------------------------------
1 | source 'https://github.com/CocoaPods/Specs.git'
2 |
3 | # Uncomment this line to define a global platform for your project
4 | platform :ios, '11.0'
5 |
6 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
7 | ENV['COCOAPODS_DISABLE_STATS'] = 'true'
8 |
9 | project 'Runner', {
10 | 'Debug' => :debug,
11 | 'Profile' => :release,
12 | 'Release' => :release,
13 | }
14 |
15 | def flutter_root
16 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
17 | unless File.exist?(generated_xcode_build_settings_path)
18 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
19 | end
20 |
21 | File.foreach(generated_xcode_build_settings_path) do |line|
22 | matches = line.match(/FLUTTER_ROOT\=(.*)/)
23 | return matches[1].strip if matches
24 | end
25 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
26 | end
27 |
28 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
29 |
30 | flutter_ios_podfile_setup
31 |
32 | target 'Runner' do
33 | use_frameworks!
34 | use_modular_headers!
35 |
36 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
37 | end
38 |
39 | post_install do |installer|
40 | installer.pods_project.targets.each do |target|
41 | flutter_additional_ios_build_settings(target)
42 | end
43 | end
44 |
--------------------------------------------------------------------------------
/lc_realtime/ios/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - Alamofire (5.5.0)
3 | - audioplayers (0.0.1):
4 | - Flutter
5 | - Flutter (1.0.0)
6 | - flutter_plugin_record (0.0.1):
7 | - Flutter
8 | - fluttertoast (0.0.2):
9 | - Flutter
10 | - Toast
11 | - FMDB (2.7.5):
12 | - FMDB/standard (= 2.7.5)
13 | - FMDB/standard (2.7.5)
14 | - image_picker (0.0.1):
15 | - Flutter
16 | - LeanCloud/Foundation (17.10.1):
17 | - Alamofire (~> 5.4)
18 | - LeanCloud/RTM-no-local-storage (17.10.1):
19 | - LeanCloud/Foundation (= 17.10.1)
20 | - SwiftProtobuf (~> 1.18)
21 | - leancloud_official_plugin (0.0.1):
22 | - Flutter
23 | - LeanCloud/RTM-no-local-storage (~> 17.10)
24 | - path_provider_ios (0.0.1):
25 | - Flutter
26 | - shared_preferences_ios (0.0.1):
27 | - Flutter
28 | - sqflite (0.0.2):
29 | - Flutter
30 | - FMDB (>= 2.7.5)
31 | - SwiftProtobuf (1.18.0)
32 | - Toast (4.0.0)
33 |
34 | DEPENDENCIES:
35 | - audioplayers (from `.symlinks/plugins/audioplayers/ios`)
36 | - Flutter (from `Flutter`)
37 | - flutter_plugin_record (from `.symlinks/plugins/flutter_plugin_record/ios`)
38 | - fluttertoast (from `.symlinks/plugins/fluttertoast/ios`)
39 | - image_picker (from `.symlinks/plugins/image_picker/ios`)
40 | - leancloud_official_plugin (from `.symlinks/plugins/leancloud_official_plugin/ios`)
41 | - path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`)
42 | - shared_preferences_ios (from `.symlinks/plugins/shared_preferences_ios/ios`)
43 | - sqflite (from `.symlinks/plugins/sqflite/ios`)
44 |
45 | SPEC REPOS:
46 | https://github.com/CocoaPods/Specs.git:
47 | - Alamofire
48 | - FMDB
49 | - LeanCloud
50 | - SwiftProtobuf
51 | - Toast
52 |
53 | EXTERNAL SOURCES:
54 | audioplayers:
55 | :path: ".symlinks/plugins/audioplayers/ios"
56 | Flutter:
57 | :path: Flutter
58 | flutter_plugin_record:
59 | :path: ".symlinks/plugins/flutter_plugin_record/ios"
60 | fluttertoast:
61 | :path: ".symlinks/plugins/fluttertoast/ios"
62 | image_picker:
63 | :path: ".symlinks/plugins/image_picker/ios"
64 | leancloud_official_plugin:
65 | :path: ".symlinks/plugins/leancloud_official_plugin/ios"
66 | path_provider_ios:
67 | :path: ".symlinks/plugins/path_provider_ios/ios"
68 | shared_preferences_ios:
69 | :path: ".symlinks/plugins/shared_preferences_ios/ios"
70 | sqflite:
71 | :path: ".symlinks/plugins/sqflite/ios"
72 |
73 | SPEC CHECKSUMS:
74 | Alamofire: 1c4fb5369c3fe93d2857c780d8bbe09f06f97e7c
75 | audioplayers: 455322b54050b30ea4b1af7cd9e9d105f74efa8c
76 | Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a
77 | flutter_plugin_record: 562ded56f3a109d769e72c3ef52ef20d835493d4
78 | fluttertoast: 6122fa75143e992b1d3470f61000f591a798cc58
79 | FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
80 | image_picker: 9aa50e1d8cdacdbed739e925b7eea16d014367e6
81 | LeanCloud: e6de4b8129ab68be7f70a9b77c4304f71c5a1a2c
82 | leancloud_official_plugin: 6f30dc57a7f181193f511355c17519a61dce033d
83 | path_provider_ios: 7d7ce634493af4477d156294792024ec3485acd5
84 | shared_preferences_ios: aef470a42dc4675a1cdd50e3158b42e3d1232b32
85 | sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904
86 | SwiftProtobuf: c3c12645230d9b09c72267e0de89468c5543bd86
87 | Toast: 91b396c56ee72a5790816f40d3a94dd357abc196
88 |
89 | PODFILE CHECKSUM: 216a07bd17c29f43047bcc707524116833a4fb33
90 |
91 | COCOAPODS: 1.11.2
92 |
--------------------------------------------------------------------------------
/lc_realtime/ios/Runner.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
11 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
12 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
13 | 75D38B816F724647BCB5345C /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6717F1ECB7B06F8CEF021B36 /* Pods_Runner.framework */; };
14 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
15 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
16 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
17 | /* End PBXBuildFile section */
18 |
19 | /* Begin PBXCopyFilesBuildPhase section */
20 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = {
21 | isa = PBXCopyFilesBuildPhase;
22 | buildActionMask = 2147483647;
23 | dstPath = "";
24 | dstSubfolderSpec = 10;
25 | files = (
26 | );
27 | name = "Embed Frameworks";
28 | runOnlyForDeploymentPostprocessing = 0;
29 | };
30 | /* End PBXCopyFilesBuildPhase section */
31 |
32 | /* Begin PBXFileReference section */
33 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; };
34 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; };
35 | 27DD645B83EB9C5FC47E9415 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; };
36 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
37 | 5E77470B24F6709B006FA0C7 /* RunnerDebug.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = RunnerDebug.entitlements; sourceTree = ""; };
38 | 5E77470C24F670B6006FA0C7 /* RunnerRelease.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = RunnerRelease.entitlements; sourceTree = ""; };
39 | 6717F1ECB7B06F8CEF021B36 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
40 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; };
41 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
42 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; };
43 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; };
44 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; };
45 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
46 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
47 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
48 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
49 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
50 | CD0B25761FAADF9218BF981B /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; };
51 | D14C5338F76FC1C167E1563A /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; };
52 | /* End PBXFileReference section */
53 |
54 | /* Begin PBXFrameworksBuildPhase section */
55 | 97C146EB1CF9000F007C117D /* Frameworks */ = {
56 | isa = PBXFrameworksBuildPhase;
57 | buildActionMask = 2147483647;
58 | files = (
59 | 75D38B816F724647BCB5345C /* Pods_Runner.framework in Frameworks */,
60 | );
61 | runOnlyForDeploymentPostprocessing = 0;
62 | };
63 | /* End PBXFrameworksBuildPhase section */
64 |
65 | /* Begin PBXGroup section */
66 | 3EEE743274DC7BDA887AFCD8 /* Frameworks */ = {
67 | isa = PBXGroup;
68 | children = (
69 | 6717F1ECB7B06F8CEF021B36 /* Pods_Runner.framework */,
70 | );
71 | name = Frameworks;
72 | sourceTree = "";
73 | };
74 | 9740EEB11CF90186004384FC /* Flutter */ = {
75 | isa = PBXGroup;
76 | children = (
77 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
78 | 9740EEB21CF90195004384FC /* Debug.xcconfig */,
79 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
80 | 9740EEB31CF90195004384FC /* Generated.xcconfig */,
81 | );
82 | name = Flutter;
83 | sourceTree = "";
84 | };
85 | 97C146E51CF9000F007C117D = {
86 | isa = PBXGroup;
87 | children = (
88 | 9740EEB11CF90186004384FC /* Flutter */,
89 | 97C146F01CF9000F007C117D /* Runner */,
90 | 97C146EF1CF9000F007C117D /* Products */,
91 | C038014A027BE48EF318F892 /* Pods */,
92 | 3EEE743274DC7BDA887AFCD8 /* Frameworks */,
93 | );
94 | sourceTree = "";
95 | };
96 | 97C146EF1CF9000F007C117D /* Products */ = {
97 | isa = PBXGroup;
98 | children = (
99 | 97C146EE1CF9000F007C117D /* Runner.app */,
100 | );
101 | name = Products;
102 | sourceTree = "";
103 | };
104 | 97C146F01CF9000F007C117D /* Runner */ = {
105 | isa = PBXGroup;
106 | children = (
107 | 5E77470C24F670B6006FA0C7 /* RunnerRelease.entitlements */,
108 | 5E77470B24F6709B006FA0C7 /* RunnerDebug.entitlements */,
109 | 97C146FA1CF9000F007C117D /* Main.storyboard */,
110 | 97C146FD1CF9000F007C117D /* Assets.xcassets */,
111 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
112 | 97C147021CF9000F007C117D /* Info.plist */,
113 | 97C146F11CF9000F007C117D /* Supporting Files */,
114 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
115 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
116 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
117 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
118 | );
119 | path = Runner;
120 | sourceTree = "";
121 | };
122 | 97C146F11CF9000F007C117D /* Supporting Files */ = {
123 | isa = PBXGroup;
124 | children = (
125 | );
126 | name = "Supporting Files";
127 | sourceTree = "";
128 | };
129 | C038014A027BE48EF318F892 /* Pods */ = {
130 | isa = PBXGroup;
131 | children = (
132 | CD0B25761FAADF9218BF981B /* Pods-Runner.debug.xcconfig */,
133 | 27DD645B83EB9C5FC47E9415 /* Pods-Runner.release.xcconfig */,
134 | D14C5338F76FC1C167E1563A /* Pods-Runner.profile.xcconfig */,
135 | );
136 | path = Pods;
137 | sourceTree = "";
138 | };
139 | /* End PBXGroup section */
140 |
141 | /* Begin PBXNativeTarget section */
142 | 97C146ED1CF9000F007C117D /* Runner */ = {
143 | isa = PBXNativeTarget;
144 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
145 | buildPhases = (
146 | 4FEDB0401F4C7531A6C93068 /* [CP] Check Pods Manifest.lock */,
147 | 9740EEB61CF901F6004384FC /* Run Script */,
148 | 97C146EA1CF9000F007C117D /* Sources */,
149 | 97C146EB1CF9000F007C117D /* Frameworks */,
150 | 97C146EC1CF9000F007C117D /* Resources */,
151 | 9705A1C41CF9048500538489 /* Embed Frameworks */,
152 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
153 | E0B72C6678CA091ED1272C26 /* [CP] Embed Pods Frameworks */,
154 | );
155 | buildRules = (
156 | );
157 | dependencies = (
158 | );
159 | name = Runner;
160 | productName = Runner;
161 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
162 | productType = "com.apple.product-type.application";
163 | };
164 | /* End PBXNativeTarget section */
165 |
166 | /* Begin PBXProject section */
167 | 97C146E61CF9000F007C117D /* Project object */ = {
168 | isa = PBXProject;
169 | attributes = {
170 | LastUpgradeCheck = 1020;
171 | ORGANIZATIONNAME = "The Chromium Authors";
172 | TargetAttributes = {
173 | 97C146ED1CF9000F007C117D = {
174 | CreatedOnToolsVersion = 7.3.1;
175 | DevelopmentTeam = 7J5XFNL99Q;
176 | LastSwiftMigration = 1100;
177 | ProvisioningStyle = Automatic;
178 | };
179 | };
180 | };
181 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
182 | compatibilityVersion = "Xcode 3.2";
183 | developmentRegion = en;
184 | hasScannedForEncodings = 0;
185 | knownRegions = (
186 | en,
187 | Base,
188 | );
189 | mainGroup = 97C146E51CF9000F007C117D;
190 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
191 | projectDirPath = "";
192 | projectRoot = "";
193 | targets = (
194 | 97C146ED1CF9000F007C117D /* Runner */,
195 | );
196 | };
197 | /* End PBXProject section */
198 |
199 | /* Begin PBXResourcesBuildPhase section */
200 | 97C146EC1CF9000F007C117D /* Resources */ = {
201 | isa = PBXResourcesBuildPhase;
202 | buildActionMask = 2147483647;
203 | files = (
204 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
205 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
206 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
207 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
208 | );
209 | runOnlyForDeploymentPostprocessing = 0;
210 | };
211 | /* End PBXResourcesBuildPhase section */
212 |
213 | /* Begin PBXShellScriptBuildPhase section */
214 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
215 | isa = PBXShellScriptBuildPhase;
216 | buildActionMask = 2147483647;
217 | files = (
218 | );
219 | inputPaths = (
220 | );
221 | name = "Thin Binary";
222 | outputPaths = (
223 | );
224 | runOnlyForDeploymentPostprocessing = 0;
225 | shellPath = /bin/sh;
226 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
227 | };
228 | 4FEDB0401F4C7531A6C93068 /* [CP] Check Pods Manifest.lock */ = {
229 | isa = PBXShellScriptBuildPhase;
230 | buildActionMask = 2147483647;
231 | files = (
232 | );
233 | inputFileListPaths = (
234 | );
235 | inputPaths = (
236 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
237 | "${PODS_ROOT}/Manifest.lock",
238 | );
239 | name = "[CP] Check Pods Manifest.lock";
240 | outputFileListPaths = (
241 | );
242 | outputPaths = (
243 | "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
244 | );
245 | runOnlyForDeploymentPostprocessing = 0;
246 | shellPath = /bin/sh;
247 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
248 | showEnvVarsInLog = 0;
249 | };
250 | 9740EEB61CF901F6004384FC /* Run Script */ = {
251 | isa = PBXShellScriptBuildPhase;
252 | buildActionMask = 2147483647;
253 | files = (
254 | );
255 | inputPaths = (
256 | );
257 | name = "Run Script";
258 | outputPaths = (
259 | );
260 | runOnlyForDeploymentPostprocessing = 0;
261 | shellPath = /bin/sh;
262 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
263 | };
264 | E0B72C6678CA091ED1272C26 /* [CP] Embed Pods Frameworks */ = {
265 | isa = PBXShellScriptBuildPhase;
266 | buildActionMask = 2147483647;
267 | files = (
268 | );
269 | inputPaths = (
270 | "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
271 | "${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework",
272 | "${BUILT_PRODUCTS_DIR}/FMDB/FMDB.framework",
273 | "${PODS_ROOT}/../Flutter/Flutter.framework",
274 | "${BUILT_PRODUCTS_DIR}/LeanCloud/LeanCloud.framework",
275 | "${BUILT_PRODUCTS_DIR}/SwiftProtobuf/SwiftProtobuf.framework",
276 | "${BUILT_PRODUCTS_DIR}/audioplayers/audioplayers.framework",
277 | "${BUILT_PRODUCTS_DIR}/flutter_plugin_record/flutter_plugin_record.framework",
278 | "${BUILT_PRODUCTS_DIR}/fluttertoast/fluttertoast.framework",
279 | "${BUILT_PRODUCTS_DIR}/image_picker/image_picker.framework",
280 | "${BUILT_PRODUCTS_DIR}/leancloud_official_plugin/leancloud_official_plugin.framework",
281 | "${BUILT_PRODUCTS_DIR}/path_provider/path_provider.framework",
282 | "${BUILT_PRODUCTS_DIR}/shared_preferences/shared_preferences.framework",
283 | "${BUILT_PRODUCTS_DIR}/sqflite/sqflite.framework",
284 | );
285 | name = "[CP] Embed Pods Frameworks";
286 | outputPaths = (
287 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Alamofire.framework",
288 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FMDB.framework",
289 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework",
290 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/LeanCloud.framework",
291 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftProtobuf.framework",
292 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/audioplayers.framework",
293 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_plugin_record.framework",
294 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/fluttertoast.framework",
295 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/image_picker.framework",
296 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/leancloud_official_plugin.framework",
297 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider.framework",
298 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/shared_preferences.framework",
299 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqflite.framework",
300 | );
301 | runOnlyForDeploymentPostprocessing = 0;
302 | shellPath = /bin/sh;
303 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
304 | showEnvVarsInLog = 0;
305 | };
306 | /* End PBXShellScriptBuildPhase section */
307 |
308 | /* Begin PBXSourcesBuildPhase section */
309 | 97C146EA1CF9000F007C117D /* Sources */ = {
310 | isa = PBXSourcesBuildPhase;
311 | buildActionMask = 2147483647;
312 | files = (
313 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
314 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
315 | );
316 | runOnlyForDeploymentPostprocessing = 0;
317 | };
318 | /* End PBXSourcesBuildPhase section */
319 |
320 | /* Begin PBXVariantGroup section */
321 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = {
322 | isa = PBXVariantGroup;
323 | children = (
324 | 97C146FB1CF9000F007C117D /* Base */,
325 | );
326 | name = Main.storyboard;
327 | sourceTree = "";
328 | };
329 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
330 | isa = PBXVariantGroup;
331 | children = (
332 | 97C147001CF9000F007C117D /* Base */,
333 | );
334 | name = LaunchScreen.storyboard;
335 | sourceTree = "";
336 | };
337 | /* End PBXVariantGroup section */
338 |
339 | /* Begin XCBuildConfiguration section */
340 | 249021D3217E4FDB00AE95B9 /* Profile */ = {
341 | isa = XCBuildConfiguration;
342 | buildSettings = {
343 | ALWAYS_SEARCH_USER_PATHS = NO;
344 | CLANG_ANALYZER_NONNULL = YES;
345 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
346 | CLANG_CXX_LIBRARY = "libc++";
347 | CLANG_ENABLE_MODULES = YES;
348 | CLANG_ENABLE_OBJC_ARC = YES;
349 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
350 | CLANG_WARN_BOOL_CONVERSION = YES;
351 | CLANG_WARN_COMMA = YES;
352 | CLANG_WARN_CONSTANT_CONVERSION = YES;
353 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
354 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
355 | CLANG_WARN_EMPTY_BODY = YES;
356 | CLANG_WARN_ENUM_CONVERSION = YES;
357 | CLANG_WARN_INFINITE_RECURSION = YES;
358 | CLANG_WARN_INT_CONVERSION = YES;
359 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
360 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
361 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
362 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
363 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
364 | CLANG_WARN_STRICT_PROTOTYPES = YES;
365 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
366 | CLANG_WARN_UNREACHABLE_CODE = YES;
367 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
368 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
369 | COPY_PHASE_STRIP = NO;
370 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
371 | ENABLE_NS_ASSERTIONS = NO;
372 | ENABLE_STRICT_OBJC_MSGSEND = YES;
373 | GCC_C_LANGUAGE_STANDARD = gnu99;
374 | GCC_NO_COMMON_BLOCKS = YES;
375 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
376 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
377 | GCC_WARN_UNDECLARED_SELECTOR = YES;
378 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
379 | GCC_WARN_UNUSED_FUNCTION = YES;
380 | GCC_WARN_UNUSED_VARIABLE = YES;
381 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
382 | MTL_ENABLE_DEBUG_INFO = NO;
383 | SDKROOT = iphoneos;
384 | SUPPORTED_PLATFORMS = iphoneos;
385 | TARGETED_DEVICE_FAMILY = "1,2";
386 | VALIDATE_PRODUCT = YES;
387 | };
388 | name = Profile;
389 | };
390 | 249021D4217E4FDB00AE95B9 /* Profile */ = {
391 | isa = XCBuildConfiguration;
392 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
393 | buildSettings = {
394 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
395 | CLANG_ENABLE_MODULES = YES;
396 | CODE_SIGN_IDENTITY = "Apple Development";
397 | CODE_SIGN_STYLE = Automatic;
398 | CURRENT_PROJECT_VERSION = 10;
399 | DEVELOPMENT_TEAM = 7J5XFNL99Q;
400 | ENABLE_BITCODE = NO;
401 | FRAMEWORK_SEARCH_PATHS = (
402 | "$(inherited)",
403 | "$(PROJECT_DIR)/Flutter",
404 | );
405 | INFOPLIST_FILE = Runner/Info.plist;
406 | IPHONEOS_DEPLOYMENT_TARGET = 10.0;
407 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
408 | LIBRARY_SEARCH_PATHS = (
409 | "$(inherited)",
410 | "$(PROJECT_DIR)/Flutter",
411 | );
412 | PRODUCT_BUNDLE_IDENTIFIER = leancloud.flutterRealtimeApp;
413 | PRODUCT_NAME = "$(TARGET_NAME)";
414 | PROVISIONING_PROFILE_SPECIFIER = "";
415 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
416 | SWIFT_VERSION = 5.0;
417 | VERSIONING_SYSTEM = "apple-generic";
418 | };
419 | name = Profile;
420 | };
421 | 97C147031CF9000F007C117D /* Debug */ = {
422 | isa = XCBuildConfiguration;
423 | buildSettings = {
424 | ALWAYS_SEARCH_USER_PATHS = NO;
425 | CLANG_ANALYZER_NONNULL = YES;
426 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
427 | CLANG_CXX_LIBRARY = "libc++";
428 | CLANG_ENABLE_MODULES = YES;
429 | CLANG_ENABLE_OBJC_ARC = YES;
430 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
431 | CLANG_WARN_BOOL_CONVERSION = YES;
432 | CLANG_WARN_COMMA = YES;
433 | CLANG_WARN_CONSTANT_CONVERSION = YES;
434 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
435 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
436 | CLANG_WARN_EMPTY_BODY = YES;
437 | CLANG_WARN_ENUM_CONVERSION = YES;
438 | CLANG_WARN_INFINITE_RECURSION = YES;
439 | CLANG_WARN_INT_CONVERSION = YES;
440 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
441 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
442 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
443 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
444 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
445 | CLANG_WARN_STRICT_PROTOTYPES = YES;
446 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
447 | CLANG_WARN_UNREACHABLE_CODE = YES;
448 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
449 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
450 | COPY_PHASE_STRIP = NO;
451 | DEBUG_INFORMATION_FORMAT = dwarf;
452 | ENABLE_STRICT_OBJC_MSGSEND = YES;
453 | ENABLE_TESTABILITY = YES;
454 | GCC_C_LANGUAGE_STANDARD = gnu99;
455 | GCC_DYNAMIC_NO_PIC = NO;
456 | GCC_NO_COMMON_BLOCKS = YES;
457 | GCC_OPTIMIZATION_LEVEL = 0;
458 | GCC_PREPROCESSOR_DEFINITIONS = (
459 | "DEBUG=1",
460 | "$(inherited)",
461 | );
462 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
463 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
464 | GCC_WARN_UNDECLARED_SELECTOR = YES;
465 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
466 | GCC_WARN_UNUSED_FUNCTION = YES;
467 | GCC_WARN_UNUSED_VARIABLE = YES;
468 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
469 | MTL_ENABLE_DEBUG_INFO = YES;
470 | ONLY_ACTIVE_ARCH = YES;
471 | SDKROOT = iphoneos;
472 | TARGETED_DEVICE_FAMILY = "1,2";
473 | };
474 | name = Debug;
475 | };
476 | 97C147041CF9000F007C117D /* Release */ = {
477 | isa = XCBuildConfiguration;
478 | buildSettings = {
479 | ALWAYS_SEARCH_USER_PATHS = NO;
480 | CLANG_ANALYZER_NONNULL = YES;
481 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
482 | CLANG_CXX_LIBRARY = "libc++";
483 | CLANG_ENABLE_MODULES = YES;
484 | CLANG_ENABLE_OBJC_ARC = YES;
485 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
486 | CLANG_WARN_BOOL_CONVERSION = YES;
487 | CLANG_WARN_COMMA = YES;
488 | CLANG_WARN_CONSTANT_CONVERSION = YES;
489 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
490 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
491 | CLANG_WARN_EMPTY_BODY = YES;
492 | CLANG_WARN_ENUM_CONVERSION = YES;
493 | CLANG_WARN_INFINITE_RECURSION = YES;
494 | CLANG_WARN_INT_CONVERSION = YES;
495 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
496 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
497 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
498 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
499 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
500 | CLANG_WARN_STRICT_PROTOTYPES = YES;
501 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
502 | CLANG_WARN_UNREACHABLE_CODE = YES;
503 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
504 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
505 | COPY_PHASE_STRIP = NO;
506 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
507 | ENABLE_NS_ASSERTIONS = NO;
508 | ENABLE_STRICT_OBJC_MSGSEND = YES;
509 | GCC_C_LANGUAGE_STANDARD = gnu99;
510 | GCC_NO_COMMON_BLOCKS = YES;
511 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
512 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
513 | GCC_WARN_UNDECLARED_SELECTOR = YES;
514 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
515 | GCC_WARN_UNUSED_FUNCTION = YES;
516 | GCC_WARN_UNUSED_VARIABLE = YES;
517 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
518 | MTL_ENABLE_DEBUG_INFO = NO;
519 | SDKROOT = iphoneos;
520 | SUPPORTED_PLATFORMS = iphoneos;
521 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
522 | TARGETED_DEVICE_FAMILY = "1,2";
523 | VALIDATE_PRODUCT = YES;
524 | };
525 | name = Release;
526 | };
527 | 97C147061CF9000F007C117D /* Debug */ = {
528 | isa = XCBuildConfiguration;
529 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
530 | buildSettings = {
531 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
532 | CLANG_ENABLE_MODULES = YES;
533 | CODE_SIGN_ENTITLEMENTS = Runner/RunnerDebug.entitlements;
534 | CODE_SIGN_IDENTITY = "Apple Development: Beijing sui (LGJ84F26F9)";
535 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
536 | CODE_SIGN_STYLE = Automatic;
537 | CURRENT_PROJECT_VERSION = 10;
538 | DEVELOPMENT_TEAM = 7J5XFNL99Q;
539 | ENABLE_BITCODE = NO;
540 | FRAMEWORK_SEARCH_PATHS = (
541 | "$(inherited)",
542 | "$(PROJECT_DIR)/Flutter",
543 | );
544 | INFOPLIST_FILE = Runner/Info.plist;
545 | IPHONEOS_DEPLOYMENT_TARGET = 10.0;
546 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
547 | LIBRARY_SEARCH_PATHS = (
548 | "$(inherited)",
549 | "$(PROJECT_DIR)/Flutter",
550 | );
551 | PRODUCT_BUNDLE_IDENTIFIER = leancloud.flutterRealtimeApp;
552 | PRODUCT_NAME = "$(TARGET_NAME)";
553 | PROVISIONING_PROFILE_SPECIFIER = "";
554 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
555 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
556 | SWIFT_VERSION = 5.0;
557 | VERSIONING_SYSTEM = "apple-generic";
558 | };
559 | name = Debug;
560 | };
561 | 97C147071CF9000F007C117D /* Release */ = {
562 | isa = XCBuildConfiguration;
563 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
564 | buildSettings = {
565 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
566 | CLANG_ENABLE_MODULES = YES;
567 | CODE_SIGN_ENTITLEMENTS = Runner/RunnerRelease.entitlements;
568 | CODE_SIGN_IDENTITY = "Apple Development";
569 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
570 | CODE_SIGN_STYLE = Automatic;
571 | CURRENT_PROJECT_VERSION = 10;
572 | DEVELOPMENT_TEAM = 7J5XFNL99Q;
573 | ENABLE_BITCODE = NO;
574 | FRAMEWORK_SEARCH_PATHS = (
575 | "$(inherited)",
576 | "$(PROJECT_DIR)/Flutter",
577 | );
578 | INFOPLIST_FILE = Runner/Info.plist;
579 | IPHONEOS_DEPLOYMENT_TARGET = 10.0;
580 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
581 | LIBRARY_SEARCH_PATHS = (
582 | "$(inherited)",
583 | "$(PROJECT_DIR)/Flutter",
584 | );
585 | PRODUCT_BUNDLE_IDENTIFIER = leancloud.flutterRealtimeApp;
586 | PRODUCT_NAME = "$(TARGET_NAME)";
587 | PROVISIONING_PROFILE_SPECIFIER = "";
588 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
589 | SWIFT_VERSION = 5.0;
590 | VERSIONING_SYSTEM = "apple-generic";
591 | };
592 | name = Release;
593 | };
594 | /* End XCBuildConfiguration section */
595 |
596 | /* Begin XCConfigurationList section */
597 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
598 | isa = XCConfigurationList;
599 | buildConfigurations = (
600 | 97C147031CF9000F007C117D /* Debug */,
601 | 97C147041CF9000F007C117D /* Release */,
602 | 249021D3217E4FDB00AE95B9 /* Profile */,
603 | );
604 | defaultConfigurationIsVisible = 0;
605 | defaultConfigurationName = Release;
606 | };
607 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
608 | isa = XCConfigurationList;
609 | buildConfigurations = (
610 | 97C147061CF9000F007C117D /* Debug */,
611 | 97C147071CF9000F007C117D /* Release */,
612 | 249021D4217E4FDB00AE95B9 /* Profile */,
613 | );
614 | defaultConfigurationIsVisible = 0;
615 | defaultConfigurationName = Release;
616 | };
617 | /* End XCConfigurationList section */
618 | };
619 | rootObject = 97C146E61CF9000F007C117D /* Project object */;
620 | }
621 |
--------------------------------------------------------------------------------
/lc_realtime/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/lc_realtime/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
37 |
38 |
39 |
40 |
41 |
42 |
52 |
54 |
60 |
61 |
62 |
63 |
69 |
71 |
77 |
78 |
79 |
80 |
82 |
83 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/lc_realtime/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/lc_realtime/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/lc_realtime/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/lc_realtime/ios/Runner/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import Flutter
2 | import LeanCloud
3 | import UserNotifications
4 |
5 | @UIApplicationMain
6 | @objc class AppDelegate: FlutterAppDelegate {
7 | override func application(
8 | _ application: UIApplication,
9 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
10 | ) -> Bool {
11 | do {
12 |
13 | LCApplication.logLevel = .all
14 | try LCApplication.default.set(
15 | id: "1eUivazFXYwJvuGpPl2LE4uY-gzGzoHsz",
16 | key: "nLMIaQSwIsHfF206PnOFoYYa",
17 | serverURL: "https://1euivazf.lc-cn-n1-shared.com")
18 | GeneratedPluginRegistrant.register(with: self)
19 | /*
20 | register APNs to access token, like this:
21 | */
22 | UNUserNotificationCenter.current().getNotificationSettings { (settings) in
23 | switch settings.authorizationStatus {
24 | case .authorized:
25 | DispatchQueue.main.async {
26 | UIApplication.shared.registerForRemoteNotifications()
27 | }
28 | case .notDetermined:
29 | UNUserNotificationCenter.current().requestAuthorization(options: [.badge, .alert, .sound]) { (granted, error) in
30 | if granted {
31 | DispatchQueue.main.async {
32 | UIApplication.shared.registerForRemoteNotifications()
33 | }
34 | }
35 | }
36 | default:
37 | break
38 | }
39 | _ = LCApplication.default.currentInstallation
40 | }
41 | return super.application(application, didFinishLaunchingWithOptions: launchOptions)
42 | } catch {
43 | fatalError("\(error)")
44 | }
45 | }
46 |
47 | override func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
48 | print("测试")
49 | /*
50 | set APNs deviceToken and Team ID.
51 | */
52 | LCApplication.default.currentInstallation.set(
53 | deviceToken: deviceToken,
54 | apnsTeamId: "7J5XFNL99Q")
55 | /*
56 | save to LeanCloud.
57 | */
58 | LCApplication.default.currentInstallation.save { (result) in
59 | switch result {
60 | case .success:
61 | break
62 | case .failure(error: let error):
63 | print(error)
64 | }
65 | }
66 | }
67 | override func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
68 | print(error)
69 | }
70 |
71 | override func applicationDidBecomeActive(_ application: UIApplication) {
72 | //本地清空角标
73 | application.applicationIconBadgeNumber = 0
74 | //currentInstallation 的角标清零
75 | LCApplication.default.currentInstallation.badge = 0
76 | LCApplication.default.currentInstallation.save { (result) in
77 | switch result {
78 | case .success:
79 | break
80 | case .failure(error: let error):
81 | print(error)
82 | }
83 | }
84 |
85 | }
86 | }
87 |
88 |
89 |
--------------------------------------------------------------------------------
/lc_realtime/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "Icon-App-20x20@2x.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "Icon-App-20x20@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "Icon-App-29x29@1x.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "Icon-App-29x29@2x.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "29x29",
29 | "idiom" : "iphone",
30 | "filename" : "Icon-App-29x29@3x.png",
31 | "scale" : "3x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "Icon-App-40x40@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "40x40",
41 | "idiom" : "iphone",
42 | "filename" : "Icon-App-40x40@3x.png",
43 | "scale" : "3x"
44 | },
45 | {
46 | "size" : "60x60",
47 | "idiom" : "iphone",
48 | "filename" : "Icon-App-60x60@2x.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "60x60",
53 | "idiom" : "iphone",
54 | "filename" : "Icon-App-60x60@3x.png",
55 | "scale" : "3x"
56 | },
57 | {
58 | "size" : "20x20",
59 | "idiom" : "ipad",
60 | "filename" : "Icon-App-20x20@1x.png",
61 | "scale" : "1x"
62 | },
63 | {
64 | "size" : "20x20",
65 | "idiom" : "ipad",
66 | "filename" : "Icon-App-20x20@2x.png",
67 | "scale" : "2x"
68 | },
69 | {
70 | "size" : "29x29",
71 | "idiom" : "ipad",
72 | "filename" : "Icon-App-29x29@1x.png",
73 | "scale" : "1x"
74 | },
75 | {
76 | "size" : "29x29",
77 | "idiom" : "ipad",
78 | "filename" : "Icon-App-29x29@2x.png",
79 | "scale" : "2x"
80 | },
81 | {
82 | "size" : "40x40",
83 | "idiom" : "ipad",
84 | "filename" : "Icon-App-40x40@1x.png",
85 | "scale" : "1x"
86 | },
87 | {
88 | "size" : "40x40",
89 | "idiom" : "ipad",
90 | "filename" : "Icon-App-40x40@2x.png",
91 | "scale" : "2x"
92 | },
93 | {
94 | "size" : "76x76",
95 | "idiom" : "ipad",
96 | "filename" : "Icon-App-76x76@1x.png",
97 | "scale" : "1x"
98 | },
99 | {
100 | "size" : "76x76",
101 | "idiom" : "ipad",
102 | "filename" : "Icon-App-76x76@2x.png",
103 | "scale" : "2x"
104 | },
105 | {
106 | "size" : "83.5x83.5",
107 | "idiom" : "ipad",
108 | "filename" : "Icon-App-83.5x83.5@2x.png",
109 | "scale" : "2x"
110 | },
111 | {
112 | "size" : "1024x1024",
113 | "idiom" : "ios-marketing",
114 | "filename" : "Icon-App-1024x1024@1x.png",
115 | "scale" : "1x"
116 | }
117 | ],
118 | "info" : {
119 | "version" : 1,
120 | "author" : "xcode"
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/lc_realtime/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SXiaoXu/FlutterRealtimeDemo/d0e9998e1d168bb7d68cd9a06e7e66c182e036cd/lc_realtime/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
--------------------------------------------------------------------------------
/lc_realtime/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SXiaoXu/FlutterRealtimeDemo/d0e9998e1d168bb7d68cd9a06e7e66c182e036cd/lc_realtime/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
--------------------------------------------------------------------------------
/lc_realtime/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SXiaoXu/FlutterRealtimeDemo/d0e9998e1d168bb7d68cd9a06e7e66c182e036cd/lc_realtime/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
--------------------------------------------------------------------------------
/lc_realtime/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SXiaoXu/FlutterRealtimeDemo/d0e9998e1d168bb7d68cd9a06e7e66c182e036cd/lc_realtime/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
--------------------------------------------------------------------------------
/lc_realtime/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SXiaoXu/FlutterRealtimeDemo/d0e9998e1d168bb7d68cd9a06e7e66c182e036cd/lc_realtime/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
--------------------------------------------------------------------------------
/lc_realtime/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SXiaoXu/FlutterRealtimeDemo/d0e9998e1d168bb7d68cd9a06e7e66c182e036cd/lc_realtime/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
--------------------------------------------------------------------------------
/lc_realtime/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SXiaoXu/FlutterRealtimeDemo/d0e9998e1d168bb7d68cd9a06e7e66c182e036cd/lc_realtime/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
--------------------------------------------------------------------------------
/lc_realtime/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SXiaoXu/FlutterRealtimeDemo/d0e9998e1d168bb7d68cd9a06e7e66c182e036cd/lc_realtime/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
--------------------------------------------------------------------------------
/lc_realtime/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SXiaoXu/FlutterRealtimeDemo/d0e9998e1d168bb7d68cd9a06e7e66c182e036cd/lc_realtime/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
--------------------------------------------------------------------------------
/lc_realtime/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SXiaoXu/FlutterRealtimeDemo/d0e9998e1d168bb7d68cd9a06e7e66c182e036cd/lc_realtime/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/lc_realtime/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SXiaoXu/FlutterRealtimeDemo/d0e9998e1d168bb7d68cd9a06e7e66c182e036cd/lc_realtime/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
--------------------------------------------------------------------------------
/lc_realtime/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SXiaoXu/FlutterRealtimeDemo/d0e9998e1d168bb7d68cd9a06e7e66c182e036cd/lc_realtime/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/lc_realtime/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SXiaoXu/FlutterRealtimeDemo/d0e9998e1d168bb7d68cd9a06e7e66c182e036cd/lc_realtime/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
--------------------------------------------------------------------------------
/lc_realtime/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SXiaoXu/FlutterRealtimeDemo/d0e9998e1d168bb7d68cd9a06e7e66c182e036cd/lc_realtime/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/lc_realtime/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SXiaoXu/FlutterRealtimeDemo/d0e9998e1d168bb7d68cd9a06e7e66c182e036cd/lc_realtime/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/lc_realtime/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "LaunchImage.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "LaunchImage@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "LaunchImage@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/lc_realtime/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SXiaoXu/FlutterRealtimeDemo/d0e9998e1d168bb7d68cd9a06e7e66c182e036cd/lc_realtime/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/lc_realtime/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SXiaoXu/FlutterRealtimeDemo/d0e9998e1d168bb7d68cd9a06e7e66c182e036cd/lc_realtime/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/lc_realtime/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SXiaoXu/FlutterRealtimeDemo/d0e9998e1d168bb7d68cd9a06e7e66c182e036cd/lc_realtime/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/lc_realtime/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md:
--------------------------------------------------------------------------------
1 | # Launch Screen Assets
2 |
3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory.
4 |
5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
--------------------------------------------------------------------------------
/lc_realtime/ios/Runner/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/lc_realtime/ios/Runner/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/lc_realtime/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | LeanMessage
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | $(FLUTTER_BUILD_NAME)
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(CURRENT_PROJECT_VERSION)
23 | LSRequiresIPhoneOS
24 |
25 | NSAppTransportSecurity
26 |
27 | NSAllowsArbitraryLoads
28 |
29 |
30 | NSCameraUsageDescription
31 | 发送图片功能需要访问您的相机。如果不允许,你将无法在聊天过程中发送图片消息。
32 | NSMicrophoneUsageDescription
33 | 录音功能需要访问麦克风,如果不允许,你将无法在聊天过程中发送语音消息。
34 | NSPhotoLibraryUsageDescription
35 | 发送图片功能需要访问您的相册。如果不允许,你将无法在聊天过程中发送相册中的图片。
36 | UIBackgroundModes
37 |
38 | remote-notification
39 |
40 | UILaunchStoryboardName
41 | LaunchScreen
42 | UIMainStoryboardFile
43 | Main
44 | UISupportedInterfaceOrientations
45 |
46 | UIInterfaceOrientationPortrait
47 | UIInterfaceOrientationLandscapeLeft
48 | UIInterfaceOrientationLandscapeRight
49 |
50 | UISupportedInterfaceOrientations~ipad
51 |
52 | UIInterfaceOrientationPortrait
53 | UIInterfaceOrientationPortraitUpsideDown
54 | UIInterfaceOrientationLandscapeLeft
55 | UIInterfaceOrientationLandscapeRight
56 |
57 | UIViewControllerBasedStatusBarAppearance
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/lc_realtime/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
--------------------------------------------------------------------------------
/lc_realtime/ios/Runner/RunnerDebug.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | aps-environment
6 | development
7 |
8 |
9 |
--------------------------------------------------------------------------------
/lc_realtime/ios/Runner/RunnerRelease.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | aps-environment
6 | development
7 |
8 |
9 |
--------------------------------------------------------------------------------
/lc_realtime/lib/Common/Global.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:fluttertoast/fluttertoast.dart';
3 | import 'package:leancloud_official_plugin/leancloud_plugin.dart';
4 | import 'package:leancloud_storage/leancloud.dart';
5 | import 'package:shared_preferences/shared_preferences.dart';
6 |
7 | enum MyEvent {
8 | NewMessage,
9 | ScrollviewDidScroll,
10 | ImageMessageHeight,
11 | PlayAudioMessage,
12 | ConversationRefresh
13 | }
14 |
15 | //TextMessage 文本消息
16 | //ImageMessage 图像消息
17 | //AudioMessage 音频消息
18 | //VideoMessage 视频消息
19 | //FileMessage 普通文件消息(.txt/.doc/.md 等各种)
20 | //LocationMessage 地理位置消息
21 |
22 | enum MyMessageType {
23 | TextMessage,
24 | ImageMessage,
25 | AudioMessage,
26 | VideoMessage,
27 | FileMessage,
28 | LocationMessage
29 | }
30 |
31 | void showToastRed(String msg) {
32 | Fluttertoast.showToast(
33 | msg: msg,
34 | toastLength: Toast.LENGTH_SHORT,
35 | gravity: ToastGravity.CENTER,
36 | timeInSecForIosWeb: 1,
37 | backgroundColor: Colors.red,
38 | textColor: Colors.white,
39 | fontSize: 20.0);
40 | }
41 |
42 | void showToastGreen(String msg) {
43 | Fluttertoast.showToast(
44 | msg: msg,
45 | toastLength: Toast.LENGTH_SHORT,
46 | gravity: ToastGravity.CENTER,
47 | timeInSecForIosWeb: 1,
48 | backgroundColor: Colors.green,
49 | textColor: Colors.white,
50 | fontSize: 20.0);
51 | }
52 |
53 | List allClients() {
54 | List list = [
55 | 'Tom',
56 | 'Jerry',
57 | 'Bob',
58 | 'Mary',
59 | 'Linda',
60 | 'Bill',
61 | 'XiaoHong',
62 | 'Lisa',
63 | 'Object',
64 | 'LC',
65 | 'William',
66 | 'robot',
67 | ];
68 | return list;
69 | }
70 |
71 | String getMessageString(Message message) {
72 | String messageString = '';
73 | if (message.binaryContent != null) {
74 | print('收到二进制消息:${message.binaryContent.toString()}');
75 | messageString = '收到二进制消息';
76 | } else if (message is TextMessage) {
77 | print('收到文本类型消息:${message.text}');
78 | messageString = message.text;
79 | } else if (message is LocationMessage) {
80 | print('收到地理位置消息,坐标:${message.latitude},${message.longitude}');
81 | messageString = '地理位置消息';
82 | } else if (message is FileMessage) {
83 | if (message is ImageMessage) {
84 | print('收到图像消息,图像 URL:${message.url}');
85 | messageString = '收到图像消息';
86 | } else if (message is AudioMessage) {
87 | print('收到音频消息,消息时长:${message.duration}');
88 | messageString = '收到语音消息';
89 | } else if (message is VideoMessage) {
90 | print('收到视频消息,消息时长:${message.duration}');
91 | messageString = '收到视频消息';
92 | } else {
93 | print('收到.txt/.doc/.md 等各种类型的普通文件消息,URL:${message.url}');
94 | messageString = '收到文件消息';
95 | }
96 | }
97 | // else if (message is CustomMessage) {
98 | // // CustomMessage 是自定义的消息类型
99 | // print('收到自定义类型消息');
100 | // }
101 | else {
102 | // 这里可以继续添加自定义类型的判断条件
103 | print('收到未知消息类型');
104 | messageString = '未知消息类型';
105 | // if (message.stringContent != null) {
106 | // print('收到普通消息:${message.stringContent}');
107 | // lastMessage = message.stringContent;
108 | // }
109 | }
110 | return messageString;
111 | }
112 |
113 | ///根据给定的日期得到format后的日期
114 | String getFormatDate(String dateOriginal) {
115 | if (dateOriginal == null) {
116 | return '';
117 | }
118 | //现在的日期
119 | var today = DateTime.now();
120 | //今天的23:59:59
121 | var standardDate = DateTime(today.year, today.month, today.day, 23, 59, 59);
122 | //传入的日期与今天的23:59:59秒进行比较
123 | Duration diff = standardDate.difference(DateTime.parse(dateOriginal));
124 | if (diff < Duration(days: 1)) {
125 | //今天
126 | // 09:20
127 | return dateOriginal.substring(11, 16);
128 | } else if (diff >= Duration(days: 1) && diff < Duration(days: 2)) {
129 | //昨天
130 | //昨天 09:20
131 | return "昨天 " + dateOriginal.substring(11, 16);
132 | } else {
133 | //昨天之前
134 | // 2019-01-23 09:20
135 | return dateOriginal.substring(0, 16);
136 | }
137 | }
138 |
139 | class CommonUtil {
140 | static Future showLoadingDialog(BuildContext context) {
141 | return showDialog(
142 | context: context,
143 | builder: (BuildContext context) {
144 | return new Material(
145 | color: Colors.transparent,
146 | child: WillPopScope(
147 | onWillPop: () => new Future.value(false),
148 | child: Center(
149 | child: new CircularProgressIndicator(),
150 | )));
151 | });
152 | }
153 | }
154 |
155 | class Global {
156 | static SharedPreferences _prefs;
157 | static String clientID;
158 |
159 | //初始化全局信息,会在APP启动时执行
160 | static Future init() async {
161 | _prefs = await SharedPreferences.getInstance();
162 |
163 | var _profile = _prefs.getString("clientID");
164 | if (_profile != null) {
165 | try {
166 | clientID = _profile;
167 | } catch (e) {
168 | print(e);
169 | }
170 | }
171 | LeanCloud.initialize(
172 | '1eUivazFXYwJvuGpPl2LE4uY-gzGzoHsz', 'nLMIaQSwIsHfF206PnOFoYYa',
173 | server: 'https://1euivazf.lc-cn-n1-shared.com',
174 | queryCache: new LCQueryCache());
175 | }
176 |
177 | static saveClientID(String id) {
178 | _prefs.setString("clienidtID", id);
179 | clientID = id;
180 | }
181 |
182 | static removeClientID() {
183 | _prefs.remove("clientID");
184 | _prefs.clear();
185 | }
186 | }
187 |
--------------------------------------------------------------------------------
/lc_realtime/lib/Models/CurrentClient.dart:
--------------------------------------------------------------------------------
1 | import 'package:leancloud_official_plugin/leancloud_plugin.dart';
2 | import 'package:flutter/material.dart';
3 | import '../Common/Global.dart';
4 |
5 | class CurrentClient {
6 | factory CurrentClient() => _sharedInstance();
7 | static CurrentClient _instance = CurrentClient._();
8 | Client client ;
9 |
10 | CurrentClient._() {
11 | print('初始化');
12 | client = Client(id: Global.clientID);
13 | }
14 |
15 | static CurrentClient _sharedInstance() {
16 | return _instance;
17 | }
18 |
19 | void updateClient(){
20 | client = Client(id: Global.clientID);
21 | }
22 | //
23 | // void open() async {
24 | // print('clint.open');
25 | //// await client.open();
26 | // }
27 | }
28 |
--------------------------------------------------------------------------------
/lc_realtime/lib/Routes/ContactsPage.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:lcrealtime/Common/Global.dart';
3 | import 'package:lcrealtime/Models/CurrentClient.dart';
4 | import 'package:leancloud_official_plugin/leancloud_plugin.dart';
5 | import 'package:leancloud_storage/leancloud.dart';
6 | import 'ConversationDetailPage.dart';
7 |
8 | class ContactsPage extends StatefulWidget {
9 | @override
10 | _ContactsPageState createState() => new _ContactsPageState();
11 | }
12 |
13 | class _ContactsPageState extends State {
14 | List _list = allClients();
15 | @override
16 | void initState() {
17 | super.initState();
18 | removeCurrentClient();
19 | }
20 |
21 | removeCurrentClient() {
22 | _list.remove(Global.clientID);
23 | setState(() {});
24 | }
25 |
26 | @override
27 | Widget build(BuildContext context) {
28 | return Column(children: [
29 | Expanded(
30 | child: ListView.separated(
31 | //添加分割线
32 | separatorBuilder: (BuildContext context, int index) {
33 | return new Divider(
34 | height: 0.8,
35 | color: Colors.grey,
36 | );
37 | },
38 | itemCount: _list.length,
39 | // itemExtent: 50.0, //强制高度为50.0
40 | itemBuilder: (BuildContext context, int index) {
41 | return GestureDetector(
42 | onTap: () {
43 | showConfirmDialog(_list[index]);
44 | },
45 |
46 | child: ListTile(title: Text(_list[index])),
47 | );
48 | }),
49 | ),
50 | ]);
51 | }
52 |
53 | void addBlackList(String clientID) async {
54 | if (Global.clientID != null) {
55 |
56 | LCObject blackList = LCObject('BlackList');
57 | blackList['clientID'] = Global.clientID;
58 | blackList.addAllUnique('blackedList', [clientID]);
59 | await blackList.save();
60 | showToastGreen('加入黑名单成功!');
61 | _list.remove(clientID);
62 | setState(() {
63 | });
64 |
65 | // try {
66 | // Conversation conversation = await currentClient.client.createConversation(
67 | // isUnique: true,
68 | // members: {clientID},
69 | // name: Global.clientID + ' & ' + clientID);
70 | //
71 | // Navigator.push(
72 | // context,
73 | // new MaterialPageRoute(
74 | // builder: (context) =>
75 | // new ConversationDetailPage(conversation: conversation),
76 | // ),
77 | // );
78 | // } catch (e) {
79 | // showToastRed('创建会话失败:${e.message}');
80 | // }
81 | } else {
82 | showToastRed('用户未登录');
83 | return;
84 | }
85 | }
86 | Future showConfirmDialog(String name) async {
87 | return showDialog(
88 | context: context,
89 | builder: (context) {
90 | return AlertDialog(
91 | title: Text("加入黑名单"),
92 | content: Text("确认将 $name 加入黑名单,不再接收其任何消息吗?"),
93 | actions: [
94 | FlatButton(
95 | child: Text("取消"),
96 | onPressed: () => Navigator.of(context).pop(), // 关闭对话框
97 | ),
98 | FlatButton(
99 | child: Text("确认"),
100 | onPressed: () {
101 | addBlackList(name);
102 | //关闭对话框并返回true
103 | Navigator.of(context).pop();
104 | },
105 | ),
106 | ],
107 | );
108 | },
109 | );
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/lc_realtime/lib/Routes/ConversationDetailPage.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:lcrealtime/Common/Global.dart';
3 | import 'package:lcrealtime/Models/CurrentClient.dart';
4 | import 'package:lcrealtime/States/GlobalEvent.dart';
5 | import 'package:lcrealtime/Widgets/MessageList.dart';
6 | import 'package:lcrealtime/Widgets/InputMessageView.dart';
7 | import 'package:leancloud_official_plugin/leancloud_plugin.dart';
8 |
9 | class ConversationDetailPage extends StatefulWidget {
10 | final Conversation conversation;
11 |
12 | ConversationDetailPage({Key key, @required this.conversation})
13 | : super(key: key);
14 | @override
15 | _ConversationDetailPageState createState() =>
16 | new _ConversationDetailPageState();
17 | }
18 |
19 | class _ConversationDetailPageState extends State {
20 | // ScrollController _scrollController = ScrollController(keepScrollOffset: true);
21 | TextEditingController renameController = TextEditingController();
22 |
23 | Message _firstMessage;
24 | CurrentClient currentClint;
25 |
26 | @override
27 | void initState() {
28 | super.initState();
29 | currentClint = CurrentClient();
30 | //进入会话详情页面,标记会话已读
31 | this.widget.conversation.read();
32 | print(this.widget.conversation.id);
33 |
34 |
35 |
36 |
37 |
38 | }
39 |
40 | @override
41 | void deactivate() async {
42 | super.deactivate();
43 | // //刷新列表
44 | // mess.emit(MyEvent.ConversationRefresh);
45 | }
46 |
47 | @override
48 | Widget build(BuildContext context) {
49 | return Scaffold(
50 | appBar: AppBar(
51 | centerTitle: true,
52 | title: Text(this.widget.conversation.name),
53 | actions: [
54 | IconButton(
55 | icon: Icon(Icons.settings, color: Colors.white),
56 | onPressed: () {
57 | showConfirmDialog();
58 | },
59 | )
60 | ],
61 | ),
62 | body: Container(
63 | padding: EdgeInsets.fromLTRB(10, 10, 10, 20),
64 | child: FutureBuilder>(
65 | future: queryMessages(),
66 | builder: (BuildContext context, AsyncSnapshot snapshot) {
67 | // 请求已结束
68 | if (snapshot.connectionState == ConnectionState.done) {
69 | if (snapshot.hasError) {
70 | return Container(
71 | height: 60.0,
72 | child: Center(
73 | child: Text("Error: ${snapshot.error}"),
74 | ),
75 | );
76 | } else {
77 | return Column(
78 | children: [
79 | MessageList(
80 | // scrollController: _scrollController,
81 | conversation: this.widget.conversation,
82 | firstPageMessages: snapshot.data,
83 | firstMessage: _firstMessage),
84 | InputMessageView(
85 | // scrollController: _scrollController,
86 | conversation: this.widget.conversation),
87 | ],
88 | );
89 | }
90 | } else {
91 | // 请求未结束,显示loading
92 | return CircularProgressIndicator();
93 | }
94 | },
95 | ),
96 | ));
97 | }
98 |
99 | void updateConInfo() async {
100 | if (renameController.text != null && renameController.text != '') {
101 | await widget.conversation.updateInfo(attributes: {
102 | 'name': renameController.text,
103 | });
104 | // setState(() {});
105 |
106 |
107 | List conversations;
108 | ConversationQuery query = currentClint.client.conversationQuery();
109 | query.whereEqualTo('objectId', widget.conversation.id);
110 |
111 | conversations = await query.find();
112 | Conversation conversationFirst = conversations.first;
113 | print('name--->' + conversationFirst.name);
114 |
115 |
116 | } else {
117 | showToastRed('名称不能为空');
118 | }
119 | }
120 |
121 | Future showConfirmDialog() async {
122 | return showDialog(
123 | context: context,
124 | builder: (context) {
125 | return AlertDialog(
126 | title: Text(
127 | "修改会话名称:",
128 | style: new TextStyle(
129 | fontWeight: FontWeight.normal,
130 | ),
131 | ),
132 | content: TextField(
133 | controller: renameController,
134 | ),
135 | actions: [
136 | FlatButton(
137 | child: Text("取消"),
138 | onPressed: () => Navigator.of(context).pop(), // 关闭对话框
139 | ),
140 | FlatButton(
141 | child: Text("确认"),
142 | onPressed: () {
143 | updateConInfo();
144 | //关闭对话框并返回true
145 | Navigator.of(context).pop();
146 | },
147 | ),
148 | ],
149 | );
150 | },
151 | );
152 | }
153 |
154 | Future> queryMessages() async {
155 | List messages;
156 | try {
157 | messages = await this.widget.conversation.queryMessage(
158 | limit: 10,
159 | );
160 | _firstMessage = messages.first;
161 | } catch (e) {
162 | print(e.message);
163 | }
164 | return messages;
165 | }
166 | }
167 |
--------------------------------------------------------------------------------
/lc_realtime/lib/Routes/ConversationListPage.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:lcrealtime/Models/CurrentClient.dart';
3 | import 'package:lcrealtime/Routes/ConversationDetailPage.dart';
4 | import 'package:lcrealtime/Widgets/TextWidget.dart';
5 | import 'package:shared_preferences/shared_preferences.dart';
6 | import '../Common/Global.dart';
7 | import 'package:leancloud_official_plugin/leancloud_plugin.dart';
8 | import 'package:lcrealtime/States/GlobalEvent.dart';
9 |
10 | class ConversationListPage extends StatefulWidget {
11 | @override
12 | _ConversationListPageState createState() => new _ConversationListPageState();
13 | }
14 |
15 | class _ConversationListPageState extends State {
16 | CurrentClient currentClint;
17 |
18 | Map unreadCountMap = Map();
19 | Map conversationIDToIndexMap = Map();
20 |
21 | @override
22 | void initState() {
23 | super.initState();
24 | currentClint = CurrentClient();
25 |
26 | //收到新消息
27 | currentClint.client.onMessage = ({
28 | Client client,
29 | Conversation conversation,
30 | Message message,
31 | }) {
32 | if (message != null) {
33 | receiveNewMessage(message);
34 | print('收到信息---');
35 | }
36 | };
37 | //
38 | mess.on(MyEvent.ConversationRefresh, (arg) {
39 | setState(() {});
40 | });
41 | //未读数更新通知
42 | currentClint.client.onUnreadMessageCountUpdated = ({
43 | Client client,
44 | Conversation conversation,
45 | }) {
46 | print('onUnreadMessageCountUpdated-----:' +
47 | conversation.unreadMessageCount.toString());
48 | // final prefs = await SharedPreferences.getInstance();
49 | if (conversation.unreadMessageCount != null) {
50 | // prefs.setInt(conversation.id, conversation.unreadMessageCount);
51 | unreadCountMap[conversation.id] = conversation.unreadMessageCount;
52 | } else {
53 | // prefs.setInt(conversation.id, 0);
54 | unreadCountMap[conversation.id] = 0;
55 | }
56 | setState(() {});
57 | //TODO 局部刷新
58 | // int count = unreadCountMap[conversation.id];
59 | // int index = conversationIDToIndexMap[conversation.id];
60 | // print(index.toString()+'index--');
61 | // if (count != null && index != null) {
62 | // _keyList[index].currentState.onPressed(count);
63 | // }
64 | };
65 | }
66 |
67 | void receiveNewMessage(Message message) {
68 | //收到新消息刷新页面
69 | // setState(() {});
70 | }
71 | // Future getUnReadMessageCount(String conversationId) async {
72 | // final prefs = await SharedPreferences.getInstance();
73 | // int counter = prefs.getInt(conversationId) ?? 0;
74 | // print('counter:-----:' + counter.toString());
75 | // return counter;
76 | // }
77 | //根据ID获取index
78 | @override
79 | void dispose() {
80 | super.dispose();
81 | //取消订阅
82 | mess.off(MyEvent.ConversationRefresh);
83 | }
84 |
85 | @override
86 | Widget build(BuildContext context) {
87 | return Scaffold(
88 | body: Center(
89 | // padding: EdgeInsets.all(2.0),
90 | child: FutureBuilder>(
91 | future: retrieveData(),
92 | builder: (BuildContext context, AsyncSnapshot snapshot) {
93 | // 请求已结束
94 | if (snapshot.connectionState == ConnectionState.done) {
95 | if (snapshot.hasError) {
96 | return Text("Error: ${snapshot.error}");
97 | } else {
98 | return ListView.separated(
99 | //添加分割线
100 | separatorBuilder: (BuildContext context, int index) {
101 | return new Divider(
102 | height: 0.8,
103 | color: Colors.grey,
104 | );
105 | },
106 | physics: const AlwaysScrollableScrollPhysics(),
107 | itemCount: snapshot.data.length,
108 | itemBuilder: (context, index) {
109 | Conversation con = snapshot.data[index];
110 | String name = con.name;
111 | List members = con.members;
112 | String time;
113 | String lastMessageString = '暂无新消息';
114 | if (con.lastMessage == null) {
115 | time = getFormatDate(con.updatedAt.toString());
116 | } else {
117 | time = getFormatDate(con.lastMessageDate.toString());
118 | lastMessageString = con.lastMessage.fromClientID +
119 | ':' +
120 | getMessageString(con.lastMessage);
121 | }
122 | int unreadCount = 0;
123 | if (unreadCountMap[con.id] != null) {
124 | unreadCount = unreadCountMap[con.id];
125 | }
126 | // conversationIDToIndexMap[con.id] = index;
127 | print('unreadCount:-----:' + unreadCount.toString());
128 |
129 | return GestureDetector(
130 | onTap: () {
131 | Conversation con = snapshot.data[index];
132 | onTapEvent(con);
133 | }, //点击
134 | child: Container(
135 | padding: const EdgeInsets.all(10),
136 | color: Colors.white,
137 | child: Row(
138 | children: [
139 | new Expanded(
140 | flex: 2,
141 | child: new Column(
142 | crossAxisAlignment: CrossAxisAlignment.start,
143 | children: [
144 | new Container(
145 | padding: const EdgeInsets.only(
146 | bottom: 8.0, right: 8, left: 10),
147 | child: Row(
148 | mainAxisAlignment:
149 | MainAxisAlignment.start,
150 | children: [
151 | Container(
152 | padding: const EdgeInsets.only(
153 | right: 4,
154 | ),
155 | child: Text(
156 | name,
157 | style: new TextStyle(
158 | fontWeight: FontWeight.bold,
159 | ),
160 | ),
161 | ),
162 | buildUnReadCountView(unreadCount),
163 | ],
164 | ),
165 | ),
166 | new Container(
167 | padding: const EdgeInsets.only(
168 | bottom: 8.0, right: 8, left: 10),
169 | child: new Text(
170 | members.toString(),
171 | style: new TextStyle(
172 | color: Colors.grey[600],
173 | ),
174 | ),
175 | ),
176 | new Container(
177 | padding: const EdgeInsets.only(
178 | right: 8, left: 10),
179 | child: new Text(
180 | lastMessageString,
181 | style: new TextStyle(
182 | color: Colors.black87,
183 | ),
184 | ),
185 | ),
186 | ],
187 | ),
188 | ),
189 | new Expanded(
190 | flex: 1,
191 | child: new Column(
192 | crossAxisAlignment: CrossAxisAlignment.end,
193 | children: [
194 | new Container(
195 | padding: const EdgeInsets.only(
196 | bottom: 0, right: 0),
197 | child: new Text(
198 | time,
199 | style: new TextStyle(
200 | color: Colors.black54,
201 | ),
202 | ),
203 | ),
204 | ],
205 | ),
206 | ),
207 | ],
208 | ),
209 | ));
210 | },
211 | );
212 | }
213 | } else {
214 | // 请求未结束,显示loading
215 | return CircularProgressIndicator();
216 | }
217 | },
218 | ),
219 | ),
220 | );
221 | }
222 |
223 | Widget buildUnReadCountView(int count) {
224 | if (count > 0) {
225 | String showNum = '';
226 | if (count < 10) {
227 | showNum = ''' ''' + count.toString() + ''' ''';
228 | } else {
229 | showNum = count.toString();
230 | }
231 | return DecoratedBox(
232 | decoration: BoxDecoration(
233 | gradient: LinearGradient(colors: [Colors.red, Colors.red]),
234 | borderRadius: BorderRadius.circular(16.0), //圆角
235 | ),
236 | child: Padding(
237 | padding: EdgeInsets.symmetric(horizontal: 3.0, vertical: 3.0),
238 | // child: TextWidget(_keyList[index])));
239 | child: Text(
240 | showNum,
241 | style: TextStyle(
242 | color: Colors.white,
243 | fontSize: 12.0,
244 | ),
245 | )));
246 | } else {
247 | return Container(
248 | height: 0,
249 | );
250 | }
251 | }
252 |
253 | void onTapEvent(Conversation con) {
254 | Navigator.push(
255 | context,
256 | new MaterialPageRoute(
257 | builder: (context) => new ConversationDetailPage(conversation: con),
258 | ),
259 | );
260 | }
261 |
262 | Future> retrieveData() async {
263 | CurrentClient currentClient = CurrentClient();
264 | List conversations;
265 | try {
266 | ConversationQuery query = currentClient.client.conversationQuery();
267 | //TODO:上拉加载更多
268 | query.limit = 20;
269 | query.orderByDescending('updatedAt');
270 | //让查询结果附带一条最新消息
271 | query.includeLastMessage = true;
272 | conversations = await query.find();
273 |
274 | //记录未读消息数
275 | final prefs = await SharedPreferences.getInstance();
276 | conversations.forEach((item) {
277 | if (item.unreadMessageCount != null) {
278 | // prefs.setInt(conversation.id, conversation.unreadMessageCount);
279 | unreadCountMap[item.id] = item.unreadMessageCount;
280 | } else {
281 | // prefs.setInt(conversation.id, 0);
282 | unreadCountMap[item.id] = 0;
283 | }
284 |
285 | // //之前没有值,存储一份
286 | // if (prefs.getInt(item.id) == null) {
287 | // if (item.unreadMessageCount != null) {
288 | // prefs.setInt(item.id, item.unreadMessageCount);
289 | // unreadCountMap[item.id] = item.unreadMessageCount;
290 | // } else {
291 | // prefs.setInt(item.id, 0);
292 | // unreadCountMap[item.id] = 0;
293 | // }
294 | // } else {
295 | // unreadCountMap[item.id] = prefs.getInt(item.id);
296 | // }
297 | });
298 | } catch (e) {
299 | print(e);
300 | showToastRed(e.message);
301 | }
302 | return conversations;
303 | }
304 | }
305 |
--------------------------------------------------------------------------------
/lc_realtime/lib/Routes/HomeBottomBar.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:lcrealtime/routes/ConversationListPage.dart';
3 | import 'package:lcrealtime/routes/LoginPage.dart';
4 | import 'ContactsPage.dart';
5 | import 'package:leancloud_official_plugin/leancloud_plugin.dart';
6 | import '../Common/Global.dart';
7 | import 'SelectChatMembers.dart';
8 | import 'package:lcrealtime/Models/CurrentClient.dart';
9 |
10 | class HomeBottomBarPage extends StatefulWidget {
11 | @override
12 | _HomeBottomBarPageState createState() => _HomeBottomBarPageState();
13 | }
14 |
15 | class _HomeBottomBarPageState extends State {
16 | int _currentIndex = 0; //记录当前选中的页面
17 |
18 | List _pages = [
19 | ConversationListPage(),
20 | ContactsPage(),
21 | ];
22 |
23 | @override
24 | void initState() {
25 | super.initState();
26 | }
27 |
28 | //退出
29 | Future clientClose() async {
30 | CommonUtil.showLoadingDialog(context); //发起请求前弹出loading
31 |
32 | close().then((value) {
33 | Navigator.pop(context); //销毁 loading
34 | Navigator.pushAndRemoveUntil(
35 | context,
36 | new MaterialPageRoute(builder: (context) => LoginPage()),
37 | (_) => false);
38 | }).catchError((error) {
39 | showToastRed(error.message);
40 | Navigator.pop(context); //销毁 loading
41 | });
42 | }
43 |
44 | Future showConfirmDialog() async {
45 | return showDialog(
46 | context: context,
47 | builder: (context) {
48 | return AlertDialog(
49 | title: Text("提示"),
50 | content: Text("确认退出登录"),
51 | actions: [
52 | FlatButton(
53 | child: Text("取消"),
54 | onPressed: () => Navigator.of(context).pop(), // 关闭对话框
55 | ),
56 | FlatButton(
57 | child: Text("确认"),
58 | onPressed: () {
59 | //Client close;
60 | //关闭对话框并返回true
61 | clientClose();
62 | Navigator.of(context).pop();
63 | },
64 | ),
65 | ],
66 | );
67 | },
68 | );
69 | }
70 |
71 | Align navRightButton(BuildContext context) {
72 | Align content;
73 | content = Align(
74 | alignment: Alignment.center,
75 | child: Padding(
76 | padding: EdgeInsets.only(top: 0.0),
77 | child: IconButton(
78 | icon: Icon(Icons.directions_run),
79 | onPressed: () {
80 | showConfirmDialog();
81 | }),
82 | ),
83 | );
84 | return content;
85 | }
86 |
87 | Align navLeftButton(BuildContext context) {
88 | Align content;
89 | content = Align(
90 | alignment: Alignment.center,
91 | child: Padding(
92 | padding: EdgeInsets.only(top: 0.0),
93 | child: IconButton(
94 | icon: Icon(Icons.add),
95 | onPressed: () {
96 | Navigator.push(
97 | context,
98 | new MaterialPageRoute(
99 | builder: (context) => new SelectChatMembers(),
100 | ),
101 | );
102 | }),
103 | ),
104 | );
105 | return content;
106 | }
107 |
108 | @override
109 | Widget build(BuildContext context) {
110 | return Scaffold(
111 | appBar: AppBar(
112 | //导航栏
113 | title: Text("当前用户:${Global.clientID}"),
114 | centerTitle: true,
115 | //导航栏右侧菜单
116 | actions: [
117 | navRightButton(context),
118 | ],
119 | leading: navLeftButton(context), //导航栏左侧菜单
120 | ),
121 | body: this._pages[this._currentIndex],
122 | bottomNavigationBar: BottomNavigationBar(
123 | // 底部导航
124 | items: [
125 | BottomNavigationBarItem(icon: Icon(Icons.message), title: Text('会话')),
126 | BottomNavigationBarItem(
127 | icon: Icon(Icons.perm_contact_calendar), title: Text('联系人')),
128 | ],
129 | currentIndex: this._currentIndex,
130 | fixedColor: Colors.blue,
131 | onTap: (index) {
132 | setState(() {
133 | //设置点击底部Tab的时候的页面跳转
134 | this._currentIndex = index;
135 | });
136 | },
137 | type: BottomNavigationBarType.fixed,
138 | ),
139 | );
140 | }
141 |
142 | Future close() async {
143 | if (Global.clientID != null) {
144 | CurrentClient currentClint = CurrentClient();
145 | await currentClint.client.close();
146 | Global.removeClientID();
147 | } else {
148 | showToastRed('有 BUG,重启一下试试。。。');
149 | }
150 | }
151 | }
152 |
--------------------------------------------------------------------------------
/lc_realtime/lib/Routes/LoginPage.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:lcrealtime/Models/CurrentClient.dart';
3 | import 'package:lcrealtime/Routes/UserProtocol.dart';
4 | import '../Common/Global.dart';
5 | import 'HomeBottomBar.dart';
6 |
7 | class LoginPage extends StatefulWidget {
8 | @override
9 | _LoginPageState createState() => _LoginPageState();
10 | }
11 |
12 | class _LoginPageState extends State {
13 | String _clientID;
14 | bool _checkboxSelected = true;
15 |
16 | @override
17 | void initState() {
18 | super.initState();
19 |
20 | if (Global.clientID != null) {
21 | _clientID = Global.clientID;
22 | setState(() {});
23 | }
24 | }
25 |
26 | Future userLogin(String clientID) async {
27 | CommonUtil.showLoadingDialog(context); //发起请求前弹出loading
28 | Global.saveClientID(clientID);
29 |
30 | login(clientID).then((value) {
31 | Navigator.pop(context); //销毁 loading
32 | Navigator.pushAndRemoveUntil(
33 | context,
34 | new MaterialPageRoute(builder: (context) => HomeBottomBarPage()),
35 | (_) => false);
36 | }).catchError((error) {
37 | showToastRed(error.message);
38 | Navigator.pop(context); //销毁 loading
39 | });
40 | }
41 |
42 | @override
43 | Widget build(BuildContext context) {
44 | return Scaffold(
45 | body: Form(
46 | child: ListView(
47 | padding: EdgeInsets.symmetric(horizontal: 22.0),
48 | children: [
49 | SizedBox(
50 | height: kToolbarHeight,
51 | ),
52 | SizedBox(height: 80.0),
53 | buildTitle(),
54 | SizedBox(height: 30.0),
55 | buildChooseUserDropdownButton(context),
56 | SizedBox(height: 30.0),
57 | buildCheckBox(context),
58 | buildClientOpenButton(context),
59 | ],
60 | )));
61 | }
62 |
63 | Padding buildChooseUserDropdownButton(BuildContext context) {
64 | return Padding(
65 | padding: const EdgeInsets.only(top: 8.0),
66 | child: Row(
67 | mainAxisAlignment: MainAxisAlignment.center,
68 | children: [
69 | Text('ID: '),
70 | InkWell(
71 | child: Row(
72 | mainAxisAlignment: MainAxisAlignment.start,
73 | children: [
74 | DropdownButton(
75 | value: this._clientID,
76 | onChanged: (String newValue) {
77 | setState(() {
78 | this._clientID = newValue;
79 | });
80 | },
81 | items: allClients()
82 | .map>((String value) {
83 | return DropdownMenuItem(
84 | value: value,
85 | child: Text(value),
86 | );
87 | }).toList(),
88 | ),
89 | ],
90 | ),
91 | ),
92 | ],
93 | ),
94 | );
95 | }
96 |
97 | Padding buildCheckBox(BuildContext context) {
98 | return Padding(
99 | padding: const EdgeInsets.only(top: 10),
100 | child: Row(
101 | mainAxisAlignment: MainAxisAlignment.center,
102 | children: [
103 | Checkbox(
104 | value: _checkboxSelected,
105 | activeColor: Colors.blue, //选中时的颜色
106 | onChanged: (value) {
107 | setState(() {
108 | _checkboxSelected = value;
109 | });
110 | },
111 | ),
112 | GestureDetector(
113 | child: Text(
114 | '我已阅读并同意使用协议',
115 | style: TextStyle(
116 | color: Colors.blue,
117 | decoration: TextDecoration.underline,
118 | fontSize: 15.0,
119 | ),
120 | ),
121 | onTap: () => showUserProtocolPage(), //点击
122 | )
123 | ],
124 | ),
125 | );
126 | }
127 |
128 | Align buildClientOpenButton(BuildContext context) {
129 | return Align(
130 | child: SizedBox(
131 | height: 45.0,
132 | width: 270.0,
133 | child: RaisedButton(
134 | child: Text(
135 | '开始聊天',
136 | style: TextStyle(fontSize: 18.0, color: Colors.white),
137 | ),
138 | color: Colors.blue,
139 | onPressed: () {
140 | if (!_checkboxSelected) {
141 | showToastRed('未同意用户使用协议');
142 | } else {
143 | userLogin(_clientID);
144 | }
145 | },
146 | ),
147 | ),
148 | );
149 | }
150 |
151 | Padding buildTitle() {
152 | return Padding(
153 | padding: EdgeInsets.all(8.0),
154 | child: Align(
155 | alignment: Alignment.center,
156 | child: Text(
157 | 'LeanMessage',
158 | style: TextStyle(fontSize: 26.0, color: Colors.blue),
159 | ),
160 | ));
161 | }
162 |
163 | showUserProtocolPage() {
164 | Navigator.push(
165 | context,
166 | new MaterialPageRoute(
167 | builder: (context) => new UserProtocolPage(),
168 | ),
169 | );
170 | }
171 |
172 | Future login(String clintID) async {
173 | CurrentClient currentClint = CurrentClient();
174 | if (clintID != currentClint.client.id) {
175 | currentClint.updateClient();
176 | }
177 | await currentClint.client.open();
178 | }
179 | }
180 |
--------------------------------------------------------------------------------
/lc_realtime/lib/Routes/SelectChatMembers.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:lcrealtime/Common/Global.dart';
3 | import 'package:leancloud_official_plugin/leancloud_plugin.dart';
4 | import 'ConversationDetailPage.dart';
5 |
6 | class SelectChatMembers extends StatefulWidget {
7 | @override
8 | _SelectChatMembersState createState() => new _SelectChatMembersState();
9 | }
10 |
11 | class _SelectChatMembersState extends State {
12 | List _list = allClients();
13 | Map _checkboxSelectedList = new Map();
14 | Set _selectedClientList = new Set();
15 |
16 | @override
17 | void initState() {
18 | super.initState();
19 | removeCurrentClient();
20 | }
21 | removeCurrentClient() {
22 | _list.remove(Global.clientID);
23 | _list.forEach((item) {
24 | //index:_list.indexOf(item)
25 | _checkboxSelectedList[item] = false;
26 | });
27 | // setState(() {});
28 | }
29 |
30 | @override
31 | Widget build(BuildContext context) {
32 | return Scaffold(
33 | appBar: AppBar(
34 | //导航栏
35 | title: Text("选择联系人"),
36 | centerTitle: true,
37 | //导航栏右侧菜单
38 | actions: [
39 | navRightButton(context),
40 | ]),
41 | body: Container(
42 | child: Column(children: [
43 | Expanded(
44 | child: ListView.separated(
45 | //添加分割线
46 | separatorBuilder: (BuildContext context, int index) {
47 | return new Divider(
48 | height: 0.8,
49 | color: Colors.grey,
50 | );
51 | },
52 | itemCount: _list.length,
53 | // itemExtent: 50.0, //强制高度为50.0
54 | itemBuilder: (BuildContext context, int index) {
55 | return CheckboxListTile(
56 | onChanged: (isCheck) {
57 | setState(() {
58 | _checkboxSelectedList[_list[index]] = isCheck;
59 | });
60 | },
61 | selected: false,
62 | value: _checkboxSelectedList[_list[index]],
63 | title: Text(_list[index]),
64 | controlAffinity: ListTileControlAffinity.leading,
65 | );
66 | }),
67 | ),
68 | ])));
69 | }
70 |
71 | Align navRightButton(BuildContext context) {
72 | Align content;
73 | content = Align(
74 | alignment: Alignment.center,
75 | child: Padding(
76 | padding: EdgeInsets.only(top: 0.0),
77 | child: RaisedButton(
78 | textColor: Colors.white,
79 | child: Text("完成", style: TextStyle(fontSize: 16.0)),
80 | shape: RoundedRectangleBorder(
81 | borderRadius: BorderRadius.circular(15.0)),
82 | color: Colors.blue,
83 | highlightColor: Colors.blue[900],
84 | colorBrightness: Brightness.dark,
85 | splashColor: Colors.grey,
86 | onPressed: () {
87 | createConversation();
88 | }),
89 | ),
90 | );
91 | return content;
92 | }
93 |
94 | void createConversation() async {
95 | _checkboxSelectedList.forEach((key, value) {
96 | if (value == true) {
97 | _selectedClientList.add(key);
98 | }
99 | });
100 | if (_selectedClientList.length == 0) {
101 | showToastRed('请选择成员!');
102 | return;
103 | }
104 |
105 | if (Global.clientID != null) {
106 | Client currentClient = Client(id: Global.clientID);
107 | try {
108 | Conversation conversation = await currentClient.createConversation(
109 | isUnique: true,
110 | members: _selectedClientList,
111 | name: Global.clientID + '发起群聊');
112 |
113 | Navigator.pop(context);
114 | Navigator.push(
115 | context,
116 | new MaterialPageRoute(
117 | builder: (context) =>
118 | new ConversationDetailPage(conversation: conversation),
119 | ),
120 | );
121 | } catch (e) {
122 | showToastRed('创建会话失败:${e.message}');
123 | }
124 | } else {
125 | showToastRed('用户未登录');
126 | return;
127 | }
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/lc_realtime/lib/Routes/UserProtocol.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class UserProtocolPage extends StatefulWidget {
4 | @override
5 | _UserProtocolPageState createState() => new _UserProtocolPageState();
6 | }
7 |
8 | class _UserProtocolPageState extends State {
9 | @override
10 | void initState() {
11 | super.initState();
12 | }
13 |
14 | @override
15 | Widget build(BuildContext context) {
16 | String str = '''
17 |
18 | 本软件是一款为移动通信设备提供即时通信的应用软件。用户使用本应用需接受本协议的全部条款。
19 |
20 | 1.您使用本应用的行为必须合法。
21 |
22 | 2.我们将保留基于我们的判断检查用户内容的权利。
23 |
24 | 3.您在应用内上传与发布的内容必须合法,否则您将承担全部法律责任。
25 |
26 | 4.一旦发现您上传的内容非法,我们会删除您账号下的全部数据,并禁止继续访问。
27 |
28 | 5. 禁止发布危害国家安全、泄露国家机密、破坏国家统一的内容。
29 |
30 | 6. 禁止发布煽动民族仇恨、民族歧视,破坏民族团结的内容。
31 |
32 | 7. 禁止发布破坏国家宗教政策,宣扬邪教和封建迷信的内容。
33 |
34 | 8. 禁止发布扰乱社会秩序,破坏社会稳定的谣言。
35 |
36 | 9. 禁止散步淫秽、色情、赌博、暴力、凶杀、恐怖或者教唆犯罪的内容
37 |
38 | 10. 禁止发布侮辱或者诽谤他人,侵害他人合法权益的内容
39 |
40 | 11. 禁止发布含有法律、行政法规禁止的其他内容的。
41 | ''';
42 | return Scaffold(
43 | appBar: AppBar(
44 | //导航栏
45 | title: Text("用户协议"),
46 | centerTitle: true,
47 | ),
48 | body: Scrollbar(
49 | // 显示进度条
50 | child: SingleChildScrollView(
51 | padding: EdgeInsets.all(16.0),
52 | child: Column(
53 | crossAxisAlignment: CrossAxisAlignment.start,
54 | children: [
55 | Text(str),
56 | ],
57 |
58 | ),
59 | ))
60 | );
61 | }
62 | }
--------------------------------------------------------------------------------
/lc_realtime/lib/States/ChangeNotifier.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class ChangeNotifier implements Listenable {
4 | List listeners = [];
5 | @override
6 | void addListener(VoidCallback listener) {
7 | //添加监听器
8 | listeners.add(listener);
9 | }
10 |
11 | @override
12 | void removeListener(VoidCallback listener) {
13 | //移除监听器
14 | listeners.remove(listener);
15 | }
16 |
17 | void notifyListeners() {
18 | //通知所有监听器,触发监听器回调
19 | listeners.forEach((item) => item());
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/lc_realtime/lib/States/ChangeNotifierProvider.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'InheritedWidget.dart';
3 |
4 | class ChangeNotifierProvider extends StatefulWidget {
5 | ChangeNotifierProvider({
6 | Key key,
7 | this.data,
8 | this.child,
9 | });
10 |
11 | final Widget child;
12 | final T data;
13 |
14 | //添加一个listen参数,表示是否建立依赖关系
15 | static T of(BuildContext context, {bool listen = true}) {
16 | // final type = _typeOf>();
17 | final provider = listen
18 | ? context.dependOnInheritedWidgetOfExactType>()
19 | : context
20 | .getElementForInheritedWidgetOfExactType>()
21 | ?.widget as InheritedProvider;
22 | return provider.data;
23 | }
24 |
25 | @override
26 | _ChangeNotifierProviderState createState() =>
27 | _ChangeNotifierProviderState();
28 | }
29 |
30 | class _ChangeNotifierProviderState
31 | extends State> {
32 | void update() {
33 | //如果数据发生变化(model类调用了notifyListeners),重新构建InheritedProvider
34 | setState(() => {});
35 | }
36 |
37 | @override
38 | void didUpdateWidget(ChangeNotifierProvider oldWidget) {
39 | //当Provider更新时,如果新旧数据不"==",则解绑旧数据监听,同时添加新数据监听
40 | if (widget.data != oldWidget.data) {
41 | oldWidget.data.removeListener(update);
42 | widget.data.addListener(update);
43 | }
44 | super.didUpdateWidget(oldWidget);
45 | }
46 |
47 | @override
48 | void initState() {
49 | // 给model添加监听器
50 | widget.data.addListener(update);
51 | super.initState();
52 | }
53 |
54 | @override
55 | void dispose() {
56 | // 移除model的监听器
57 | widget.data.removeListener(update);
58 | super.dispose();
59 | }
60 |
61 | @override
62 | Widget build(BuildContext context) {
63 | return InheritedProvider(
64 | data: widget.data,
65 | child: widget.child,
66 | );
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/lc_realtime/lib/States/Consumer.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'ChangeNotifierProvider.dart';
3 |
4 | // 这是一个便捷类,会获得当前context和指定数据类型的Provider
5 | class Consumer extends StatelessWidget {
6 | Consumer({
7 | Key key,
8 | @required this.builder,
9 | this.child,
10 | }) : assert(builder != null),
11 | super(key: key);
12 |
13 | final Widget child;
14 |
15 | final Widget Function(BuildContext context, T value) builder;
16 |
17 | @override
18 | Widget build(BuildContext context) {
19 | return builder(
20 | context,
21 | ChangeNotifierProvider.of(context), //自动获取Model
22 | );
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/lc_realtime/lib/States/ConversationModel.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:leancloud_official_plugin/leancloud_plugin.dart';
3 |
4 | class ConversationModel extends ChangeNotifier {
5 |
6 | //更新消息列表
7 | Future> updateMessageListView(Conversation conversation) async {
8 | List messages;
9 | try {
10 | messages = await conversation.queryMessage(
11 | limit: 100,
12 | );
13 | print(messages.length);
14 | } catch (e) {
15 | print(e.message);
16 | }
17 | return messages;
18 | }
19 |
20 | void sendNewMessage() {
21 | // 通知监听器(订阅者),重新构建InheritedProvider, 更新状态。
22 | notifyListeners();
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/lc_realtime/lib/States/GlobalEvent.dart:
--------------------------------------------------------------------------------
1 | //订阅者回调签名
2 | typedef void EventCallback(arg);
3 |
4 | class EventMessage {
5 | //私有构造函数
6 | EventMessage._internal();
7 |
8 | //保存单例
9 | static EventMessage _singleton = new EventMessage._internal();
10 |
11 | //工厂构造函数
12 | factory EventMessage()=> _singleton;
13 |
14 | //保存事件订阅者队列,key:事件名(id),value: 对应事件的订阅者队列
15 | var _emap = new Map