EMClient.h 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120
  1. /**
  2. * @header EMClient.h
  3. * @abstract SDK Client
  4. * @author Hyphenate
  5. * @version 3.00
  6. */
  7. #import <Foundation/Foundation.h>
  8. #import "EMClientDelegate.h"
  9. #import "EMError.h"
  10. #import "EMMultiDevicesDelegate.h"
  11. #import "EMOptions.h"
  12. #import "EMPushOptions.h"
  13. #import "IEMChatManager.h"
  14. #import "IEMChatroomManager.h"
  15. #import "IEMContactManager.h"
  16. #import "IEMGroupManager.h"
  17. #import "IEMThreadManager.h"
  18. #import "IEMPushManager.h"
  19. #import "IEMUserInfoManager.h"
  20. #import "IEMTranslateManager.h"
  21. #import "IEMPresenceManager.h"
  22. #import "IEMStatisticsManager.h"
  23. #import "EMDeviceConfig.h"
  24. #import "EMLocalNotificationManager.h"
  25. #import "EMTranslationResult.h"
  26. #import "EMLogDelegate.h"
  27. /**
  28. * \~chinese
  29. * 检查类型的枚举。
  30. * 开发者可以根据需求来调用 `serviceCheckWithUsername` 方法进行检查。该方法为异步方法,如果出现报错,可以确认错误信息。
  31. *
  32. * \~english
  33. * This enum lists the server diagnostic tests which are run for the current user when you call EMClient::serviceCheckWithUsername. This is an asynchronous method. If there is an error, check the error code to know the error information.
  34. */
  35. typedef NS_ENUM(NSInteger, EMServerCheckType) {
  36. EMServerCheckAccountValidation = 0, /** \~chinese 账号检查类型,账号是否有效的检查。 \~english The check of the account validity. */
  37. EMServerCheckGetDNSListFromServer, /** \~chinese 获取服务列表检查类型 \~english The check of getting DNS from the server. */
  38. EMServerCheckGetTokenFromServer, /** \~chinese 获取 token 检查类型 \~english The check of getting the token from the server. */
  39. EMServerCheckDoLogin, /** \~chinese 登录检查类型 \~english The check of the login mode. */
  40. EMServerCheckDoLogout, /** \~chinese 登出检查类型 \~english The check of the logout mode. */
  41. };
  42. /**
  43. * \~chinese
  44. * 该类为 SDK 的入口类,负责登录登出及连接管理等,由此可以获得其他模块的入口,例如:群组模块。
  45. * [EMClient sharedClient].groupManager;
  46. *
  47. * \~english
  48. * The EMClient, which is the entry point of the Chat SDK. You can log in, log out, and access other functionalities such as group and chatroom with this class.
  49. * [EMClient sharedClient].groupManager;
  50. */
  51. @interface EMClient : NSObject
  52. {
  53. EMPushOptions *_pushOptions;
  54. }
  55. /**
  56. * \~chinese
  57. * SDK 版本号。
  58. *
  59. * \~english
  60. * The SDK version number.
  61. */
  62. @property(nonatomic, strong, readonly) NSString * _Nonnull version;
  63. /**
  64. * \~chinese
  65. * 当前登录账号。
  66. *
  67. * \~english
  68. * The ID of the user currently logged into your chat app.
  69. */
  70. @property(nonatomic, strong, readonly) NSString * _Nullable currentUsername;
  71. /**
  72. * \~chinese
  73. * SDK 的设置选项。
  74. *
  75. * \~english
  76. * The SDK setting options. For example, whether to use https by default.
  77. */
  78. @property(nonatomic, strong, readonly) EMOptions * _Nonnull options;
  79. /**
  80. * \~chinese
  81. * 聊天模块。
  82. *
  83. * \~english
  84. * The chat manager module.
  85. */
  86. @property(nonatomic, strong, readonly) id<IEMChatManager> _Nullable chatManager;
  87. /**
  88. * \~chinese
  89. * 好友模块。
  90. *
  91. * \~english
  92. * The contact manager module.
  93. */
  94. @property(nonatomic, strong, readonly) id<IEMContactManager> _Nullable contactManager;
  95. /**
  96. * \~chinese
  97. * 群组模块。
  98. *
  99. * \~english
  100. * The group manager module.
  101. */
  102. @property(nonatomic, strong, readonly) id<IEMGroupManager> _Nullable groupManager;
  103. /**
  104. * \~chinese
  105. * 聊天室模块。
  106. * thread模块
  107. *
  108. * \~english
  109. * Thread Management
  110. */
  111. @property (nonatomic, strong, readonly) id<IEMThreadManager> _Nullable threadManager;
  112. /*!
  113. * \~chinese
  114. * 聊天室模块
  115. *
  116. * \~english
  117. * The chat room manager module.
  118. */
  119. @property(nonatomic, strong, readonly) id<IEMChatroomManager> _Nullable roomManager;
  120. /**
  121. * \~chinese
  122. * 推送模块。
  123. *
  124. * \~english
  125. * The push manager module.
  126. */
  127. @property (nonatomic, strong, readonly) id<IEMPushManager> _Nullable pushManager;
  128. /**
  129. * \~chinese
  130. * 是否让用户自动使用上次登录的账号登录。如果因密码错误或账号异常等原因登录失败,则该参数会被重置为 NO;如果你想使用自动登录,则需要重新将该参数设为 YES。
  131. *
  132. * \~english
  133. * Whether to let a user automatically log in to the chat server with the username used in the previous session. If the login fails, for example, because of a wrong password or the username deactivated, the isAutoLogin parameter is reset to NO, and you need to set it back to YES to allow automatic login.
  134. *
  135. */
  136. @property(nonatomic, readonly) BOOL isAutoLogin;
  137. /**
  138. * \~chinese
  139. * 用户是否已登录。
  140. *
  141. * \~english
  142. * Returns `true` if the current user is logged in.
  143. */
  144. @property(nonatomic, readonly) BOOL isLoggedIn;
  145. /**
  146. * \~chinese
  147. * SDK 是否连上聊天服务器。
  148. *
  149. * \~english
  150. * Whether the SDK is connected to the chat server.
  151. */
  152. @property(nonatomic, readonly) BOOL isConnected;
  153. /**
  154. * \~chinese
  155. * 当前用户访问聊天服务器使用的 token。用户第一次登陆的时候需要用用户 ID 和密码登陆,成功时返回 token,以后即可用 token 登陆。
  156. *
  157. * \~english
  158. * The token for accessing the current chat.
  159. */
  160. @property(nonatomic, readonly) NSString * _Nullable accessUserToken;
  161. /**
  162. * \~chinese
  163. * 用户属性模块。
  164. *
  165. * \~english
  166. * The user attributes manager module.
  167. */
  168. @property(nonatomic, strong, readonly) id<IEMUserInfoManager> _Nullable userInfoManager;
  169. /**
  170. * \~chinese
  171. * 在线状态管理模块。
  172. *
  173. * \~english
  174. * The presence manager module.
  175. */
  176. @property (nonatomic, strong, readonly) id<IEMPresenceManager> _Nullable presenceManager;
  177. /**
  178. * \~chinese
  179. * 消息流量管理模块。
  180. *
  181. * \~english
  182. * The message statistics manager module.
  183. */
  184. @property (nonatomic, strong, readonly) id<IEMStatisticsManager> _Nullable statisticsManager;
  185. /**
  186. * \~chinese
  187. * Client 类是 chat 的入口,在调用任何其他方法前,需要先调用该方法创建一个 Client 实例。
  188. *
  189. * \~english
  190. * Creates a Client instance. The Client class is the entry to the Chat SDK. You need to call this method to create a Client instance before calling any other method.
  191. */
  192. + (instancetype _Nonnull )sharedClient;
  193. /**
  194. * \~chinese
  195. * SDK 版本号。
  196. *
  197. * \~english
  198. * The SDK version number.
  199. */
  200. - (NSString *)version;
  201. #pragma mark - Delegate
  202. /**
  203. * \~chinese
  204. * 添加回调代理。
  205. *
  206. * @param aDelegate 要添加的代理。
  207. * @param aQueue 执行代理方法的队列。
  208. *
  209. * \~english
  210. * Add the EMClientDelegate, so when the delegate event occurs, the delegate will call the methods automatically in <EMClientDelegate>.
  211. *
  212. * @param aDelegate The delegate that you want to add: ClientDelegate.
  213. * @param aQueue (optional) The queue of calling delegate methods. If you want to run the app on the main thread, set this parameter as nil. */
  214. - (void)addDelegate:(id<EMClientDelegate>_Nonnull)aDelegate
  215. delegateQueue:(dispatch_queue_t _Nullable )aQueue;
  216. /**
  217. * \~chinese
  218. * 移除回调代理。
  219. *
  220. * @param aDelegate 要移除的代理。
  221. *
  222. * \~english
  223. * Remove the delegate.
  224. *
  225. * @param aDelegate The delegate that you want to remove.
  226. */
  227. - (void)removeDelegate:(id _Nonnull )aDelegate;
  228. /**
  229. * \~chinese
  230. * 添加多设备回调代理。
  231. *
  232. * @param aDelegate 要添加的代理。
  233. * @param aQueue 执行代理方法的队列。
  234. *
  235. * \~english
  236. * Add the multi-device delegate.
  237. *
  238. * @param aDelegate The delegate that you want to add: MultiDevicesDelegate.
  239. * @param aQueue The queue of calling delegate methods.
  240. */
  241. - (void)addMultiDevicesDelegate:(id<EMMultiDevicesDelegate>_Nonnull)aDelegate
  242. delegateQueue:(dispatch_queue_t _Nullable )aQueue NS_SWIFT_NAME(addMultiDevices(delegate:queue:));
  243. /**
  244. * \~chinese
  245. * 移除多设备回调代理。
  246. *
  247. * @param aDelegate 要移除的代理。
  248. *
  249. * \~english
  250. * Remove the multi-device delegate.
  251. *
  252. * @param aDelegate The multi-device delegate that you want to delete.
  253. */
  254. - (void)removeMultiDevicesDelegate:(id<EMMultiDevicesDelegate>_Nonnull)aDelegate;
  255. #pragma mark - Initialize SDK
  256. /**
  257. * \~chinese
  258. * 初始化 SDK。
  259. *
  260. * @param aOptions SDK 配置项。
  261. *
  262. * @result EMError 错误信息,包含调用失败的原因。
  263. *
  264. * \~english
  265. * Initialize the SDK.
  266. *
  267. * @param aOptions The SDK setting options: Options..
  268. *
  269. * @Result EMError A description of the issue that caused this call to fail.
  270. */
  271. - (EMError *_Nullable)initializeSDKWithOptions:(EMOptions * _Nonnull )aOptions;
  272. #pragma mark - Change AppKey
  273. /**
  274. * \~chinese
  275. * 修改 app key,注意只有在未登录状态才能修改 app key。修改 app key 是为了方便你切换其他 app key,切换后可以使用切换后的 app key 测试,除了登出外,没有其他的限制。
  276. *
  277. * @param aAppkey The app key.
  278. *
  279. * @result EMError 错误信息,包含调用失败的原因。
  280. *
  281. * \~english
  282. * Update the unique identifier used to access server.
  283. *
  284. * You retrieve the new app key from server. As this key controls all access to server for your app, you can only update the key when the current user is logged out.
  285. *
  286. * @param aAppkey The app key.
  287. *
  288. * @Result A description of the issue that caused this call to fail.
  289. */
  290. - (EMError *_Nullable)changeAppkey:(NSString * _Nonnull)aAppkey;
  291. #pragma mark - User Registeration
  292. /**
  293. * \~chinese
  294. * 注册用户。不推荐使用,建议后台通过 REST 注册。
  295. *
  296. * 同步方法,会阻塞当前线程.
  297. *
  298. * @param aUsername 用户名,长度不超过 64 个字符。请确保你对该参数设值。支持的字符包括英文字母(a-z),数字(0-9),下划线(_),英文横线(-),英文句号(.)。该参数不区分大小写,大写字母会被自动转为小写字母。如果使用正则表达式设置该参数,则可以将表达式写为:^[a-zA-Z0-9_-]+$。
  299. * @param aPassword 密码,长度不超过 64 个字符。请确保你对该参数设值。
  300. *
  301. * @result EMError 错误信息,包含调用失败的原因。
  302. *
  303. * \~english
  304. * Register a new user with your chat network.
  305. *
  306. * This method is not recommended and you are advised to call the Restful API.
  307. *
  308. * After you call `initializeSDKWithOptions` and register your app in console, the app has access to all the features registered inside your chat network. You add and remove users inside your chat network; depending on how you implement your app, you control the people each user can see inside your network.
  309. *
  310. * This is a synchronous method and blocks the current thread. To ensure registration reliability, we recommend using the REST API to register new chat users.
  311. *
  312. * @param aUsername The username. The maximum length is 64 characters. Ensure that you set this parameter. Supported characters include the 26 English letters (a-z), the ten numbers (0-9), the underscore (_), the hyphen (-), and the English period (.). This parameter is case insensitive, and upper-case letters are automatically changed to low-case ones. If you want to set this parameter as a regular expression, set it as ^[a-zA-Z0-9_-]+$.
  313. * @param aPassword The password. The maximum length is 64 characters. Ensure that you set this parameter.
  314. *
  315. * @result A description of the issue that caused this call to fail.
  316. */
  317. - (EMError *_Nullable)registerWithUsername:(NSString * _Nonnull)aUsername
  318. password:(NSString * _Nonnull)aPassword;
  319. /**
  320. * \~chinese
  321. * 注册用户。
  322. *
  323. * 不推荐使用,建议后台通过 REST 注册。
  324. *
  325. * 异步方法。
  326. *
  327. * @param aUsername 用户名,长度不超过 64 个字符。请确保你对该参数设值。支持的字符包括英文字母(a-z),数字(0-9),下划线(_),英文横线(-),英文句号(.)。该参数不区分大小写,大写字母会被自动转为小写字母。如果使用正则表达式设置该参数,则可以将表达式写为:^[a-zA-Z0-9_-]+$。
  328. * @param aPassword 密码,长度不超过 64 个字符。请确保你对该参数设值。
  329. * @param aCompletionBlock 该方法完成调用的回调。如果该方法调用失败,会包含调用失败的原因。
  330. *
  331. * \~english
  332. * Register a new user with your chat network.
  333. *
  334. * This is an asynchronous method.
  335. *
  336. * This method is not recommended and you are advised to call the Restful API.
  337. *
  338. * After you call `initializeSDKWithOptions` and register your app in console, the app has access to all the features registered inside your chat network. You add and remove users inside your chat network; depending on how you implement your app, you control the people each user can see inside your network.
  339. *
  340. * To ensure registration reliability, we recommend using the REST API to register new chat users.
  341. *
  342. * @param aUsername The username. The maximum length is 64 characters. Ensure that you set this parameter. Supported characters include the 26 English letters (a-z), the ten numbers (0-9), the underscore (_), the hyphen (-), and the English period (.). This parameter is case insensitive, and upper-case letters are automatically changed to low-case ones. If you want to set this parameter as a regular expression, set it as ^[a-zA-Z0-9_-]+$.
  343. * @param aPassword The password. The maximum length is 64 characters. Ensure that you set this parameter.
  344. * @param aCompletionBlock The completion block, which contains the username and the error message if the method fails.
  345. *
  346. */
  347. - (void)registerWithUsername:(NSString *_Nonnull)aUsername
  348. password:(NSString *_Nonnull)aPassword
  349. completion:(void (^_Nullable)(NSString * _Nonnull aUsername, EMError * _Nullable aError))aCompletionBlock;
  350. #pragma mark - Login
  351. /**
  352. * \~chinese
  353. * 从服务器获取 token。
  354. *
  355. * 异步方法。
  356. *
  357. * @param aUsername 用户名。
  358. * @param aPassword 密码。
  359. * @param aCompletionBlock 该方法完成调用的回调。如果该方法调用失败,会包含调用失败的原因。
  360. *
  361. * \~english
  362. * Fetches the token from the server.
  363. *
  364. * This is an asynchronous method.
  365. *
  366. * @param aUsername The username.
  367. * @param aPassword The password.
  368. * @param aCompletionBlock The completion block, which contains the token and the error message if the method fails.
  369. *
  370. */
  371. - (void)fetchTokenWithUsername:(NSString *_Nonnull)aUsername
  372. password:(NSString *_Nonnull)aPassword
  373. completion:(void (^_Nullable)(NSString * _Nullable aToken, EMError * _Nullable aError))aCompletionBlock;
  374. /**
  375. * \~chinese
  376. * 用户使用密码登录服务器。
  377. *
  378. * 推荐使用token登录聊天服务器
  379. *
  380. * 同步方法,会阻塞当前线程。
  381. *
  382. * @param aUsername 用户名,长度不超过 64 个字符。请确保你对该参数设值。支持的字符包括英文字母(a-z),数字(0-9),下划线(_),英文横线(-),英文句号(.)。该参数不区分大小写,大写字母会被自动转为小写字母。如果使用正则表达式设置该参数,则可以将表达式写为:^[a-zA-Z0-9_-]+$。
  383. * @param aPassword 密码,长度不超过 64 个字符。请确保你对该参数设值。
  384. *
  385. * @result EMError 错误信息,包含调用失败的原因。
  386. *
  387. * \~english
  388. * A user logs in to the chat server with a password.
  389. *
  390. * This is a synchronous method and blocks the current thread.
  391. *
  392. * It is recommended that you log in to the chat service with a token.
  393. *
  394. * @param aUsername The username. The maximum length is 64 characters. Ensure that you set this parameter. Supported characters include the 26 English letters (a-z), the ten numbers (0-9), the underscore (_), the hyphen (-), and the English period (.). This parameter is case insensitive, and upper-case letters are automatically changed to low-case ones. If you want to set this parameter as a regular expression, set it as ^[a-zA-Z0-9_-]+$.
  395. * @param aPassword The password. The maximum length is 64 characters. Ensure that you set this parameter.
  396. *
  397. * @result Returns nil on success, and the description of the issue that cause the call to fail.
  398. */
  399. - (EMError *_Nullable)loginWithUsername:(NSString *_Nonnull)aUsername
  400. password:(NSString *_Nonnull)aPassword;
  401. /**
  402. * \~chinese
  403. * 用户使用密码登录聊天服务器。
  404. *
  405. * 异步方法。
  406. *
  407. * 推荐使用token登录聊天服务器
  408. *
  409. * @param aUsername 用户名,长度不超过 64 个字符。请确保你对该参数设值。支持的字符包括英文字母(a-z),数字(0-9),下划线(_),英文横线(-),英文句号(.)。该参数不区分大小写,大写字母会被自动转为小写字母。如果使用正则表达式设置该参数,则可以将表达式写为:^[a-zA-Z0-9_-]+$。
  410. * @param aPassword 密码,长度不超过 64 个字符。请确保你对该参数设值。
  411. * @param aCompletionBlock 该方法完成调用的回调。如果该方法调用失败,会包含调用失败的原因。
  412. *
  413. * \~english
  414. * A user logs in to the chat server with a password.
  415. *
  416. * This is an asynchronous method.
  417. *
  418. * It is recommended that you log in to the chat service with a token.
  419. *
  420. * @param aUsername The username. The maximum length is 64 characters. Ensure that you set this parameter. Supported characters include the 26 English letters (a-z), the ten numbers (0-9), the underscore (_), the hyphen (-), and the English period (.). This parameter is case insensitive, and upper-case letters are automatically changed to low-case ones. If you want to set this parameter as a regular expression, set it as ^[a-zA-Z0-9_-]+$.
  421. * @param aPassword The password. The maximum length is 64 characters. Ensure that you set this parameter.
  422. * @param aCompletionBlock The completion block, which contains the username and the error message if the method fails.
  423. *
  424. */
  425. - (void)loginWithUsername:(NSString *_Nonnull)aUsername
  426. password:(NSString *_Nonnull)aPassword
  427. completion:(void (^_Nullable)(NSString * _Nonnull aUsername, EMError *_Nullable aError))aCompletionBlock;
  428. /**
  429. * \~chinese
  430. * 用户使用 token 登录。该方法支持自动登录。
  431. *
  432. * 同步方法,会阻塞当前线程。
  433. *
  434. * @param aUsername 用户名,长度不超过 64 个字符。请确保你对该参数设值。支持的字符包括英文字母(a-z),数字(0-9),下划线(_),英文横线(-),英文句号(.)。该参数不区分大小写,大写字母会被自动转为小写字母。如果使用正则表达式设置该参数,则可以将表达式写为:^[a-zA-Z0-9_-]+$。
  435. * @param aToken The token。
  436. *
  437. * @result EMError 错误信息,包含调用失败的原因。
  438. *
  439. * \~english
  440. * A user logs in to the chat server with a token. This method does not support automatic isLoggedIn.
  441. *
  442. * This is a synchronous method and blocks the current thread.
  443. *
  444. * @param aUsername The username. The maximum length is 64 characters. Ensure that you set this parameter. Supported characters include the 26 English letters (a-z), the ten numbers (0-9), the underscore (_), the hyphen (-), and the English period (.). This parameter is case insensitive, and upper-case letters are automatically changed to low-case ones. If you want to set this parameter as a regular expression, set it as ^[a-zA-Z0-9_-]+$.
  445. * @param aToken The token for user logging in to Chat server.
  446. *
  447. * @result Returns nil on success, and the description of the issue that cause the call to fail.
  448. */
  449. - (EMError *_Nullable)loginWithUsername:(NSString *_Nonnull)aUsername
  450. token:(NSString *_Nonnull)aToken;
  451. /**
  452. * \~chinese
  453. * 用户使用 token 登录。该方法支持自动登录。
  454. *
  455. * 异步方法。
  456. *
  457. * @param aUsername 用户名,长度不超过 64 个字符。请确保你对该参数设值。支持的字符包括英文字母(a-z),数字(0-9),下划线(_),英文横线(-),英文句号(.)。该参数不区分大小写,大写字母会被自动转为小写字母。如果使用正则表达式设置该参数,则可以将表达式写为:^[a-zA-Z0-9_-]+$。
  458. * @param aToken The token。
  459. * @param aCompletionBlock 该方法完成调用的回调。如果该方法调用失败,会包含调用失败的原因。
  460. *
  461. * \~english
  462. * A user logs in to the chat server with a token. This method support automatic login.
  463. *
  464. * This is an asynchronous method.
  465. *
  466. * @param aUsername The username. The maximum length is 64 characters. Ensure that you set this parameter. Supported characters include the 26 English letters (a-z), the ten numbers (0-9), the underscore (_), the hyphen (-), and the English period (.). This parameter is case insensitive, and upper-case letters are automatically changed to low-case ones. If you want to set this parameter as a regular expression, set it as ^[a-zA-Z0-9_-]+$.
  467. * @param aToken The token for logging in to the chat server.
  468. * @param aCompletionBlock The completion block, which contains the username and the error message if the method fails.
  469. *
  470. */
  471. - (void)loginWithUsername:(NSString *_Nonnull)aUsername
  472. token:(NSString *_Nonnull)aToken
  473. completion:(void (^_Nullable)(NSString * _Nonnull aUsername, EMError *_Nullable aError))aCompletionBlock;
  474. /**
  475. * \~chinese
  476. * 声网 Agora Chat user token 登录。
  477. *
  478. * 同步方法,会阻塞当前线程。
  479. *
  480. * @param aUsername 用户名
  481. * @param aAgoraToken 声网 Agora Chat user token。
  482. *
  483. * @result 成功返回 nil,如果有错误会返回错误原因。
  484. *
  485. * \~english
  486. * A user logs in to the chat server with Agora Chat user token. Supports automatic login.
  487. *
  488. * This is a synchronous method and blocks the current thread.
  489. *
  490. * @param aUsername The username.
  491. * @param aAgoraToken The Agora Chat user token.
  492. *
  493. * @result Returns nil on success, and the description of the issue that cause the call to fail.
  494. */
  495. - (EMError *_Nullable)loginWithUsername:(NSString *_Nonnull)aUsername
  496. agoraToken:(NSString *_Nonnull)aAgoraToken;
  497. /**
  498. * \~chinese
  499. * 声网 Agora Chat user token 登录。
  500. *
  501. * @param aUsername 用户名。
  502. * @param aAgoraToken 声网 Agora Chat user token。
  503. * @param aCompletionBlock 完成的回调,如果有错误会返回错误原因。
  504. *
  505. * \~english
  506. * A user logs in to the chat server with Agora Chat user token. Supports automatic login.
  507. *
  508. *
  509. * @param aUsername The username.
  510. * @param aAgoraToken The Agora Chat user token.
  511. * @param aCompletionBlock The callback of completion block, which contains the description of the cause to the issue if the method fails.
  512. *
  513. */
  514. - (void)loginWithUsername:(NSString *_Nonnull)aUsername
  515. agoraToken:(NSString *_Nonnull)aAgoraToken
  516. completion:(void (^_Nullable)(NSString * _Nonnull aUsername, EMError *_Nullable aError))aCompletionBlock;
  517. /**
  518. * \~chinese
  519. * 当用户在声网 token 登录状态时,且在 EMClientDelegate 回调中收到 token 即将过期/已经过期事件的回调通知,可以调用这个 API 来更新 token,避免因 token 失效产生的未知问题。
  520. *
  521. * 同步方法,会阻塞当前线程。
  522. *
  523. * @param newAgoraToken 新声网 token。
  524. *
  525. * @result 返回结果,如果有错误会返回错误信息。
  526. *
  527. * \~english
  528. * Renews the token when the current token expires.
  529. *
  530. * The token expires after a period of time once the token schema is enabled when:
  531. * - The SDK triggers the onTokenPrivilegeWillExpire callback, or
  532. * - The onConnectionStateChanged callback reports the CONNECTION_CHANGED_TOKEN_EXPIRED(9) error.
  533. *
  534. * The app should retrieve a new token from the server and call this method to renew it. Failure to do so results in the SDK disconnecting from the server.
  535. *
  536. * This is a synchronous method and blocks the current thread.
  537. *
  538. * @param newAgoraToken The new Agora Chat token。
  539. *
  540. * @result The result which contains the description of the cause to the failure if call fails.
  541. */
  542. - (EMError *_Nullable)renewToken:(NSString *_Nonnull)newAgoraToken;
  543. #pragma mark - Logout
  544. /**
  545. * \~chinese
  546. * 用户登出聊天服务器。
  547. *
  548. * 同步方法,会阻塞当前线程。
  549. *
  550. * @param aIsUnbindDeviceToken 是否解除账号与设备绑定。YES 表示解除绑定。成功解绑后,用户登出账号后设备将不再收到消息推送。如果你将该参数设为 YES,但解绑失败,则 SDK 会返回错误信息,包含调用失败的原因。
  551. *
  552. * @result EMError 错误信息,包含失败原因。
  553. *
  554. * \~english
  555. * A user logs out of the chat server.
  556. *
  557. * This is a synchronous method and blocks the current thread.
  558. *
  559. * @param aIsUnbindDeviceToken Whether to unbind the username from the device(Set to YES to unbind the user currently logged into the app from this device). That stops the user device receiving push notifications from the Apple Push Notifications service.
  560. *
  561. * @result A description of the issue that caused this call to fail.
  562. */
  563. - (EMError *_Nullable)logout:(BOOL)aIsUnbindDeviceToken;
  564. /**
  565. * \~chinese
  566. * 登出聊天服务器。
  567. *
  568. * 异步方法。
  569. *
  570. * @param aIsUnbindDeviceToken 是否解除账号与设备绑定。YES 表示解除绑定。成功解绑后,用户登出账号后设备将不再收到消息推送。如果你将该参数设为 YES,但解绑失败,则 SDK 会返回错误信息,包含调用失败的原因。
  571. * @param aCompletionBlock 该方法完成调用的回调。如果该方法调用失败,会包含调用失败的原因。
  572. *
  573. * \~english
  574. * A user logs out of the chat server.
  575. *
  576. * This is an asynchronous method.
  577. *
  578. * @param aIsUnbindDeviceToken Whether to unbind the username from the device. If you unbind the username from the device (setting this parameter as YES) and logs out, the device no longer receives messages from the Apple Push Notification Service.
  579. * @param aCompletionBlock The completion block, which contains the token and the error message if the method fails.
  580. *
  581. */
  582. - (void)logout:(BOOL)aIsUnbindDeviceToken
  583. completion:(void (^_Nullable)(EMError * _Nullable aError))aCompletionBlock;
  584. #pragma mark - PushKit
  585. /**
  586. * \~chinese
  587. * 绑定 PushKit token。
  588. *
  589. * 这里是苹果的 PushKit 推送服务,服务于 VOIP 类型的推送。
  590. *
  591. * 同步方法,会阻塞当前线程。
  592. *
  593. * @param aPushToken 要绑定的 token。
  594. *
  595. * @result EMError 错误信息,包含调用失败的原因。
  596. *
  597. * \~english
  598. * Use the pushkit token to bind the user and the device, which is required to enable Apple PushKit Service.
  599. *
  600. * This is a synchronous method and blocks the current thread.
  601. *
  602. * @param aPushToken The pushkit token to bind.
  603. *
  604. * @result A description of the issue that caused this call to fail.
  605. */
  606. - (EMError *_Nullable)bindPushKitToken:(NSData *_Nullable)aPushToken;
  607. /**
  608. * \~chinese
  609. * 注册 PushKit token。
  610. *
  611. * 这里是苹果的 PushKit 推送服务,服务于 VOIP 类型的推送。
  612. *
  613. * 异步方法。
  614. *
  615. * @param aPushToken 要绑定的 token。
  616. * @param aCompletionBlock 该方法完成调用的回调。如果该方法调用失败,会包含调用失败的原因。
  617. *
  618. * \~english
  619. * Register a pushkit token, this is required to enable Apple PushKit Service, which is for VOIP CALL.
  620. *
  621. * This is an asynchronous method.
  622. *
  623. * @param aPushToken The pushkit token to bind.
  624. * @param aCompletionBlock The completion block, which contains the error message if the method fails.
  625. */
  626. - (void)registerPushKitToken:(NSData *_Nullable)aPushToken
  627. completion:(void (^_Nullable)(EMError * _Nullable aError))aCompletionBlock;
  628. /**
  629. * \~chinese
  630. * 解除 PushKit token 绑定,与解除注册 `unRegisterPushKitTokenWithCompletion` 方法作用一致。
  631. *
  632. * 这里是苹果的 PushKit 推送服务,服务于 VOIP 类型的推送。
  633. *
  634. * 同步方法,会阻塞当前线程。
  635. *
  636. * @result EMError 错误信息,包含调用失败的原因。
  637. *
  638. * \~english
  639. * Unbind the Apple PushKit token.
  640. *
  641. * This is a synchronous method and blocks the current thread.
  642. *
  643. * @result A description of the issue that caused this call to fail.
  644. */
  645. - (EMError *_Nullable)unBindPushKitToken;
  646. /**
  647. * \~chinese
  648. * 解除 PushKit token 注册,与解除绑定 `unBindPushKitToken` 方法作用一致。
  649. *
  650. * 异步方法。
  651. *
  652. * 这里是苹果的 PushKit 推送服务,服务于 VOIP 类型的推送。
  653. *
  654. * \~english
  655. * Unregister the Apple PushKit token.
  656. *
  657. * @param aCompletionBlock The completion block, which contains the error message if the method fails.
  658. */
  659. - (void)unRegisterPushKitTokenWithCompletion:(void (^_Nullable)(EMError * _Nullable aError))aCompletionBlock;
  660. #pragma mark - APNs
  661. /**
  662. * \~chinese
  663. * 绑定 device token。
  664. *
  665. * Device token 用于苹果 APNS 推送。
  666. *
  667. * 同步方法,会阻塞当前线程。
  668. *
  669. * @param aDeviceToken 要绑定的 token。
  670. *
  671. * @result EMError 错误信息,包含调用失败的原因。
  672. *
  673. * \~english
  674. * Device token binding is required to enable Apple Push Notification Service.
  675. *
  676. * This is a synchronous method and blocks the current thread.
  677. *
  678. * @param aDeviceToken Device token to bind.
  679. *
  680. * @Result Returns nil on success, and the description of the issue that cause the call to fail.
  681. */
  682. - (EMError *_Nullable)bindDeviceToken:(NSData *_Nonnull)aDeviceToken;
  683. /**
  684. * \~chinese
  685. * 注册 device token。
  686. *
  687. * Device token 用于苹果 APNS 推送。
  688. *
  689. * 异步方法。
  690. *
  691. * @param aDeviceToken 要绑定的 token。
  692. * @param aCompletionBlock 该方法完成调用的回调。如果该方法调用失败,会包含调用失败的原因。
  693. *
  694. * \~english
  695. * Device token binding is required to enable Apple push notification service.
  696. *
  697. * @param aDeviceToken The device token to bind.
  698. * @param aCompletionBlock The completion block, which contains the error message if the method fails.
  699. */
  700. - (void)registerForRemoteNotificationsWithDeviceToken:(NSData *_Nonnull)aDeviceToken
  701. completion:(void (^_Nullable)(EMError *_Nullable aError))aCompletionBlock;
  702. #pragma mark - Log
  703. /**
  704. * \~chinese
  705. * 上传日志到服务器。
  706. *
  707. * 同步方法,会阻塞当前线程。
  708. *
  709. * @result 成功返回 nil,调用失败返回 error 其中包含调用失败的原因。
  710. *
  711. * \~english
  712. * Upload the log to the chat server.
  713. * The information in the debug log is used by our engineers to fix errors and improve system performance.
  714. * Make sure to use the `EMLog` class.
  715. *
  716. * This is a synchronous method and blocks the current thread.
  717. *
  718. * @result Returns nil on success, and error on failure which contains the description of the issue that cause the call to fail_Nullable.
  719. */
  720. - (EMError *_Nullable)uploadLogToServer;
  721. /**
  722. * \~chinese
  723. * 上传日志到服务器。
  724. *
  725. * @param aCompletionBlock 该方法完成调用的回调。如果该方法调用失败,会包含调用失败的原因。
  726. *
  727. * \~english
  728. * Upload debugging log to server.
  729. *
  730. * @param aCompletionBlock The completion block, which contains the token and the error message if the method fails.
  731. */
  732. - (void)uploadDebugLogToServerWithCompletion:(void (^_Nullable)(EMError *_Nullable aError))aCompletionBlock;
  733. /**
  734. * \~chinese
  735. * 将日志文件压缩成 .gz 文件,返回 gz 文件路径。强烈建议方法完成之后删除该压缩文件。
  736. *
  737. * 同步方法,会阻塞当前线程。
  738. *
  739. * @param pError 错误信息,包含调用失败的原因。
  740. *
  741. * @result NSString 文件路径。
  742. *
  743. * \~english
  744. * Compress the debug log into a gzip archive.
  745. * Best practice is to delete this debug archive as soon as it is no longer used.
  746. *
  747. * This is a synchronous method and blocks the current thread.
  748. *
  749. * @param pError A description of the issue that caused this call to fail.
  750. *
  751. * @result NSString The full filepath to the debug archive.
  752. */
  753. - (NSString *_Nullable)getLogFilesPath:(EMError **_Nullable)pError;
  754. /**
  755. * \~chinese
  756. * 将日志文件压缩成 .gz 文件,返回 gz 文件路径。强烈建议方法完成之后删除该压缩文件。
  757. *
  758. * 异步方法。
  759. *
  760. * @param aCompletionBlock 该方法完成调用的回调。如果该方法调用失败,会包含调用失败的原因。
  761. *
  762. * \~english
  763. * Compresses the log files in the format of .gz and returns the path of the compressed file. Recommends deleting the compressed file when it is no longer used.
  764. *
  765. * This is an asynchronous method.
  766. *
  767. * @param aCompletionBlock The completion block, which contains the token and the error message if the method fails.
  768. */
  769. - (void)getLogFilesPathWithCompletion:(void (^_Nullable)(NSString *_Nullable aPath, EMError * _Nullable aError))aCompletionBlock;
  770. /**
  771. * \~chinese
  772. * 输出日志信息到日志文件,需要在 SDK 初始化之后调用。
  773. *
  774. * 同步方法,会阻塞当前线程。
  775. *
  776. * @param aLog 要输出的日志信息。
  777. *
  778. * \~english
  779. * Output log info to log file. You can call this method after the SDK has been initialized.
  780. *
  781. * This is a synchronous method and blocks the current thread.
  782. *
  783. * @param aLog The log info.
  784. */
  785. - (void)log:(NSString *_Nonnull)aLog;
  786. /**
  787. * \~chinese
  788. * 添加日志回调代理。
  789. *
  790. * @param aDelegate 要添加的代理。
  791. * @param aQueue 执行代理方法的队列。
  792. *
  793. * \~english
  794. * Add the log callback delegate.
  795. *
  796. * @param aDelegate The delegate that you want to add: EMLogDelegate.
  797. * @param aQueue The queue of calling delegate methods.
  798. */
  799. - (void)addLogDelegate:(id<EMLogDelegate>_Nonnull)aDelegate
  800. delegateQueue:(dispatch_queue_t _Nullable )aQueue NS_SWIFT_NAME(addLog(delegate:queue:));
  801. /**
  802. * \~chinese
  803. * 移除日志回调代理。
  804. *
  805. * @param aDelegate 要移除的代理。
  806. *
  807. * \~english
  808. * Remove the log callback delegate.
  809. *
  810. * @param aDelegate The log callback delegate that you want to delete.
  811. */
  812. - (void)removeLogDelegate:(id<EMLogDelegate>_Nonnull)aDelegate NS_SWIFT_NAME(removeLog(delegate:));
  813. #pragma mark - Multi Devices
  814. /**
  815. * \~chinese
  816. * 从服务器获取所有已经登录的设备信息。
  817. *
  818. * 同步方法,会阻塞当前线程。
  819. *
  820. * @param aUsername 用户名。
  821. * @param aPassword 密码。
  822. * @param pError 错误信息,包含调用失败的原因。
  823. *
  824. * @result 所有已经登录的设备信息列表,由 <EMDeviceConfig> 对象组成的数组。
  825. *
  826. * \~english
  827. * Retrieve the array of devices the user is currently logged into.
  828. *
  829. * This is a synchronous method and blocks the current thread.
  830. *
  831. * @param aUsername The username.
  832. * @param aPassword The password.
  833. * @param pError A description of the issue that caused this call to fail.
  834. *
  835. * @result The information of the logged in devices, an array of <EMDeviceConfig> objects.
  836. */
  837. - (NSArray<EMDeviceConfig*> *_Nullable)getLoggedInDevicesFromServerWithUsername:(NSString * _Nonnull)aUsername
  838. password:(NSString * _Nonnull)aPassword
  839. error:(EMError ** _Nullable)pError;
  840. /**
  841. * \~chinese
  842. * 从服务器获取所有已经登录的设备信息。
  843. *
  844. * 异步方法。
  845. *
  846. * @param aUsername 用户名。
  847. * @param aPassword 密码。
  848. * @param aCompletionBlock 该方法完成调用的回调。如果该方法调用失败,会包含调用失败的原因。
  849. *
  850. * \~english
  851. * Get all the device information <EMDeviceConfig> that logged in to the server.
  852. *
  853. * This is an asynchronous method.
  854. *
  855. * @param aUsername The username.
  856. * @param aPassword The password.
  857. * @param aCompletionBlock The completion block, which contains the list and the error message if the method fails.
  858. *
  859. */
  860. - (void)getLoggedInDevicesFromServerWithUsername:(NSString *_Nonnull)aUsername
  861. password:(NSString *_Nonnull)aPassword
  862. completion:(void (^_Nullable)(NSArray<EMDeviceConfig*> * _Nullable aList, EMError *_Nullable aError))aCompletionBlock;
  863. /**
  864. * \~chinese
  865. * 强制指定的设备登出。
  866. *
  867. * 同步方法,会阻塞当前线程。
  868. *
  869. * @param aUsername 用户名。
  870. * @param aPassword 密码。
  871. * @param aResource 要登出的设备,可以通过 `getLoggedInDevicesFromServerWithUsername` 方法获取。
  872. *
  873. * @result 返回方法调用结果,如果有错误会返回错误原因。
  874. *
  875. * \~english
  876. * Kick a single user from your app installed on a specific device.
  877. *
  878. * This is a synchronous method and blocks the current thread.
  879. *
  880. * @param aUsername The username.
  881. * @param aPassword The password.
  882. * @param aResource The device to log `aUsername` out from. Call `getLoggedInDevicesFromServerWithUsername` to retrieve the list of devices `aUsername` is currently logged into.
  883. *
  884. * @result Returns nil on success, and the description of the issue that cause the call to fail.
  885. */
  886. - (EMError *_Nullable)kickDeviceWithUsername:(NSString *_Nonnull)aUsername
  887. password:(NSString *_Nonnull)aPassword
  888. resource:(NSString *_Nonnull)aResource;
  889. /**
  890. * \~chinese
  891. * 强制指定的设备登出。
  892. *
  893. * 异步方法。
  894. *
  895. * @param aUsername 用户名。
  896. * @param aPassword 密码。
  897. * @param aResource 设备信息。
  898. * @param aCompletionBlock 该方法完成调用的回调。如果该方法调用失败,会包含调用失败的原因。
  899. *
  900. * \~english
  901. * Kick a single user from your app installed on a specific device.
  902. *
  903. * The device information can be obtained from `getLoggedInDevicesFromServerWithUsername`.
  904. *
  905. * This is an asynchronous method.
  906. *
  907. * @param aUsername The username.
  908. * @param aPassword The password.
  909. * @param aResource The device to be logged out of. You can get the logged in devices through `getLoggedInDevicesFromServerWithUsername`.
  910. * @param aCompletionBlock The completion block, which contains the error message if the method fails.
  911. */
  912. - (void)kickDeviceWithUsername:(NSString *_Nonnull)aUsername
  913. password:(NSString *_Nonnull)aPassword
  914. resource:(NSString *_Nonnull)aResource
  915. completion:(void (^_Nullable)(EMError *_Nullable aError))aCompletionBlock;
  916. /**
  917. * \~chinese
  918. * 强制所有的登录设备登出。
  919. *
  920. * 同步方法,会阻塞当前线程。
  921. *
  922. * @param aUsername 用户名。
  923. * @param aPassword 密码。
  924. *
  925. * @result 返回结果,如果失败会包含调用失败的原因。
  926. *
  927. * \~english
  928. * Kicks a user from your app installed on all the devices.
  929. *
  930. * This is a synchronous method and blocks the current thread.
  931. *
  932. * @param aUsername The username.
  933. * @param aPassword The password.
  934. *
  935. * @result Returns nil on success, and the description of the issue that cause the call to fail.
  936. */
  937. - (EMError *_Nullable)kickAllDevicesWithUsername:(NSString *_Nonnull)aUsername
  938. password:(NSString *_Nonnull)aPassword;
  939. /**
  940. * \~chinese
  941. * 强制所有的登录设备登出。
  942. *
  943. * 异步方法。
  944. *
  945. * @param aUsername 用户名。
  946. * @param aPassword 密码。
  947. * @param aCompletionBlock 该方法完成调用的回调。如果该方法调用失败,会包含调用失败的原因。
  948. *
  949. * \~english
  950. * Kicks a single user from your app installed on all the devices.
  951. *
  952. * This is an asynchronous method.
  953. *
  954. * @param aUsername The username.
  955. * @param aPassword The password.
  956. * @param aCompletionBlock The completion block, which contains the error message if the method fails.
  957. */
  958. - (void)kickAllDevicesWithUsername:(NSString *_Nonnull)aUsername
  959. password:(NSString *_Nonnull)aPassword
  960. completion:(void (^_Nullable)(EMError *_Nullable aError))aCompletionBlock;
  961. /**
  962. * \~chinese
  963. * 获取当前登录的设备信息
  964. *
  965. * @result EMDeviceConfig 当前登录的设备信息
  966. *
  967. * \~english
  968. * Get Information of currently logged in device
  969. *
  970. * @result EMDeviceConfig Information of currently logged in device
  971. */
  972. - (EMDeviceConfig *)getDeviceConfig:(EMError **)pError;
  973. #pragma mark - iOS
  974. /**
  975. * \~chinese
  976. * iOS 专用,程序进入后台时,需要调用此方法断开连接。
  977. *
  978. * @param aApplication UIApplication
  979. *
  980. * \~english
  981. * Disconnects from the chat server when the app is switched to background.
  982. *
  983. * @param aApplication UIApplication
  984. */
  985. - (void)applicationDidEnterBackground:(id _Nonnull )aApplication;
  986. /**
  987. * \~chinese
  988. * iOS 专用,程序进入前台时,需要调用此方法进行重连。
  989. *
  990. * @param aApplication 当前应用程序实例。
  991. *
  992. * \~english
  993. * Reconnect to the server when your app returns to foreground mode.
  994. *
  995. * @param aApplication The current application instance.
  996. */
  997. - (void)applicationWillEnterForeground:(id _Nonnull )aApplication;
  998. /**
  999. * \~chinese
  1000. * iOS 专用,程序在前台收到 APNS 时,需要调用此方法。
  1001. *
  1002. * @param application 当前应用程序实例。
  1003. * @param userInfo 推送内容。
  1004. *
  1005. * \~english
  1006. * Occurs when your app is running in the foreground and the device receives an Apple Push Notification (APN).
  1007. *
  1008. * @param application The current application instance.
  1009. * @param userInfo The push content.
  1010. */
  1011. - (void)application:(id _Nonnull)application didReceiveRemoteNotification:(NSDictionary * _Nullable)userInfo;
  1012. #pragma mark - Service Check
  1013. /**
  1014. * \~chinese
  1015. * 服务诊断接口,根据 EMServerCheckType 枚举的顺序依次诊断当前服务,并回调给开发者。
  1016. * 如果已经登录,默认使用登录账号。
  1017. *
  1018. * 异步方法。
  1019. *
  1020. * @param aUsername 用户名。
  1021. * @param aPassword 密码。
  1022. * @param aCompletionBlock 该方法完成调用的回调。如果该方法调用失败,会包含调用失败的原因。
  1023. *
  1024. * \~english
  1025. * Run the server diagnostic tests for Agora Chat for a specific user.
  1026. * These tests are run in the order defined by EMServerCheckType.
  1027. * If the user is logged in, the login account is used by default.
  1028. *
  1029. * This is an asynchronous method.
  1030. *
  1031. * @param aUsername The username.
  1032. * @param aPassword The password.
  1033. * @param aCompletionBlock The completion block, which contains the error message if the method fails.
  1034. */
  1035. - (void)serviceCheckWithUsername:(NSString *_Nonnull)aUsername
  1036. password:(NSString *_Nonnull)aPassword
  1037. completion:(void (^_Nullable)(EMServerCheckType aType, EMError *_Nullable aError))aCompletionBlock;
  1038. @property (nonatomic, strong, readonly) id<IEMTranslateManager> _Nonnull translateManager EM_DEPRECATED_IOS(3_8_9, 3_9_5,"Use -IEMChatManager translateMessage: instead");
  1039. @end