中國(guó)品牌,讓東南亞感受“消費(fèi)升級(jí)”小紅書本地“坐抖望團(tuán)”CrowdStrike“全球滅霸響指”事件后續(xù),德國(guó) 10% 企業(yè)更換安全供應(yīng)商導(dǎo)致 1TB 數(shù)據(jù)泄露后,迪士尼宣布棄用 Slack 平臺(tái)合合信息啟信產(chǎn)業(yè)大腦攜手市北新區(qū)打造“一企一畫像”平臺(tái),加速數(shù)字化轉(zhuǎn)型重慶:力爭(zhēng)今年智能網(wǎng)聯(lián)新能源汽車產(chǎn)量突破 100 萬(wàn)輛,到 2027 年建成萬(wàn)億級(jí)產(chǎn)業(yè)集群微信iOS最新版上線:iPhone用戶可在朋友圈發(fā)實(shí)況照片了蘋果有線耳機(jī)或?qū)⑼.a(chǎn)沖上熱搜!閑魚相關(guān)搜索量暴漲384%2024 vivo開(kāi)發(fā)者大會(huì)官宣:OriginOS 5/自研藍(lán)河系統(tǒng)2降臨真·AI程序員來(lái)了,阿里云「通義靈碼」全面進(jìn)化,全流程開(kāi)發(fā)僅用幾分鐘東方甄選烤腸全網(wǎng)銷量及銷售額領(lǐng)先鴻蒙PC要來(lái)了 界面很漂亮!余承東:目前華為PC將是最后一批搭載Windows上半年中國(guó)AR/VR出貨23.3萬(wàn)臺(tái),同比下滑了 29.1%IDC:2024 上半年中國(guó) AR / VR 頭顯出貨 23.3 萬(wàn)臺(tái),同比下滑 29.1%英特爾AI加速器Gaudi3下周發(fā)布,挑戰(zhàn)NVIDIA統(tǒng)治地位!大屏技術(shù)邂逅千年色彩美學(xué)!海信激光電視成為電影《只此青綠》官方合作伙伴OpenAI將最新AI模型o1擴(kuò)展到企業(yè)和教育領(lǐng)域三星新專利探索AR技術(shù)新應(yīng)用:檢測(cè)屏幕指紋殘留,提高手機(jī)安全性猛瑪傳奇C1:直播圖傳技術(shù)的革新者JFrog推出首個(gè)運(yùn)行時(shí)安全解決方案,實(shí)現(xiàn)從代碼到云的全面軟件完整性和可追溯性
  • 首頁(yè) > 數(shù)據(jù)存儲(chǔ)頻道 > 數(shù)據(jù)庫(kù)頻道 > 操作系統(tǒng)與開(kāi)源

    開(kāi)源項(xiàng)目:用環(huán)信MQTT實(shí)現(xiàn)"世界頻道"只需5分鐘【附源碼】

    2022年04月27日 16:09:14   來(lái)源:中文科技資訊

      說(shuō)到“世界頻道”想必大家都不陌生,常見(jiàn)的如王者榮耀的世界廣播搖人組隊(duì)以及最近興起的Discord社區(qū)交友等等。究其目的就是在應(yīng)用內(nèi)讓海量用戶可以實(shí)時(shí)互動(dòng)。有些開(kāi)發(fā)者為了實(shí)現(xiàn)這種場(chǎng)景會(huì)選擇聊天室方案來(lái)實(shí)現(xiàn),但是這種方式存在一定的局限性,比如聊天室人數(shù)上限、海量消息處理等各種情況。

      當(dāng)然如果有錢有顏,可以直接選擇云廠商產(chǎn)品(比如環(huán)信的聊天室方案和超級(jí)社區(qū)),如果有才有time,也可以選擇平替版MQTT實(shí)現(xiàn)方案。今天小猿將介紹用環(huán)信MQTT消息云實(shí)現(xiàn)應(yīng)用內(nèi)的世界頻道,滿滿干貨,不要錯(cuò)過(guò)~~

      使用MQTT實(shí)現(xiàn)世界頻道-Demo效果演示

      協(xié)議優(yōu)勢(shì):

      在介紹具體方案之前,我們先嘮一嘮為啥選擇MQTT協(xié)議。

      輕量級(jí):MQTT本身是物聯(lián)網(wǎng)的連接協(xié)議,專為受限設(shè)備和低帶寬場(chǎng)景使用。所以其代碼占用空間較小,同樣適用于注重SDK大小的移動(dòng)應(yīng)用領(lǐng)域(比如:游戲領(lǐng)域)。

      易集成:MQTT作為標(biāo)準(zhǔn)開(kāi)放的消息協(xié)議,經(jīng)過(guò)多年演進(jìn),已支持30多種開(kāi)發(fā)語(yǔ)言,10余種SDK,無(wú)論何種開(kāi)發(fā)環(huán)境,都可以快速找到開(kāi)源SDK。

      高并發(fā):MQTT是輕量級(jí)的消息傳輸協(xié)議,2字節(jié)心跳報(bào)文,最小化傳輸和連接成本,云廠商broker產(chǎn)品都可支持千萬(wàn)級(jí)并發(fā)接入,適用于高并發(fā)連接場(chǎng)景。

      低成本:MQTT是基于客戶端-服務(wù)器的訂閱/發(fā)布模型,通過(guò)服務(wù)器中間件實(shí)現(xiàn)消息分發(fā),減少消息復(fù)制成本,快速實(shí)現(xiàn)一對(duì)多在線推送。

      靈活性:MQTT協(xié)議支持多種消息特性,包括:topic主題層級(jí)、消息分級(jí)(QoS0,1,2)、遺囑消息、保留消息等,可以靈活實(shí)現(xiàn)多種業(yè)務(wù)場(chǎng)景。

      衍生功能:隨著MQTT云服務(wù)的發(fā)展,部分服務(wù)器廠商已支持消息存儲(chǔ)、獲取在線設(shè)備列表、查看歷史消息等衍生功能,降低開(kāi)發(fā)工作量與消息存儲(chǔ)成本。

      實(shí)現(xiàn)方案:

      言歸正傳,上干貨。本次技術(shù)實(shí)現(xiàn)方案包含:移動(dòng)客戶端(Android)、后端服務(wù)(Java)以及MQTT服務(wù)器。這里提一下,MQTT服務(wù)器使用環(huán)信MQTT消息云,使用三方云服務(wù)比較省心,既節(jié)省開(kāi)發(fā)時(shí)間,產(chǎn)品性能也不需要擔(dān)心,現(xiàn)在注冊(cè)可以直接使用環(huán)信MQTT消息云超高額度的免費(fèi)版:每月100并發(fā)連接、300萬(wàn)消息,完全滿足功能開(kāi)發(fā)使用。

      客戶端實(shí)現(xiàn):

      客戶端實(shí)現(xiàn)主要包含以下兩部分:

      底層MQTT業(yè)務(wù)集成:包含引入SDK、MQTT方法封裝、業(yè)務(wù)交互(消息收發(fā))。

      APP上層交互:在APP首頁(yè)提供世界頻道入口,實(shí)現(xiàn)心情彈幕飄窗(接收)和發(fā)送。

      接下來(lái)上底層MQTT業(yè)務(wù)集成代碼。

      引入SDK:

      這一步環(huán)信官方文檔比較明確,就是根據(jù)自己的平臺(tái)引入相應(yīng)的mqtt客戶端sdk,這里簡(jiǎn)單貼一下AndroidStudio的引入配置

      1// 在根目錄 build.gradle repositories 下加入配置

      2maven { url "https://repo.eclipse.org/content/repositories/paho-snapshots/" }

      3...

      4// 然后加入 MQTT 依賴

      5// MQTT sdk https://docs-im.easemob.com/mqtt/qsandroidsdk

      6implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.1.0'

      7implementation 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1'

      方法封裝

      這里貼一下對(duì)mqtt相關(guān)方法的簡(jiǎn)單封裝,代碼在vmmqtt模塊兒的MQTTHelper類下:

      1 /**

      2 * Create by lzan13 on 2022/3/22

      3 * 描述:MQTT 幫助類

      4 */

      5 object MQTTHelper {

      6

      7    private var mqttClient: MqttAndroidClient? = null

      8

      9    // 緩存主題集合

      10    private val topicList = mutableListOf()

      11

      12    /**

      13     * 鏈接MQTT

      14     * @param id 用戶 Id

      15     * @param token 用戶鏈接 MQTT 的 Token

      16     * @param topic 需要訂閱的主題,不為空就會(huì)在連接成功后進(jìn)行訂閱

      17     */

      18    fun connect(id: String, token: String, topic: String = "") {

      19        // 處理訂閱主題

      20        if (topic.isNotEmpty()) topicList.add(topic)

      21

      22        // 拼接鏈接地址

      23        val url = "tcp://${MQTTConstants.mqttHost()}:${MQTTConstants.mqttPort()}"

      24        // 拼接 clientId

      25        val clientId = "${id}@${MQTTConstants.mqttAppId()}"

      26        mqttClient = MqttAndroidClient(VMTools.context, url, clientId)

      27

      28        //連接參數(shù)

      29        val options = MqttConnectOptions()

      30        options.isAutomaticReconnect = true //設(shè)置自動(dòng)重連

      31        options.isCleanSession = true // 緩存

      32        options.connectionTimeout = CConstants.timeMinute.toInt() // 設(shè)置超時(shí)時(shí)間,單位:秒

      33        options.keepAliveInterval = CConstants.timeMinute.toInt() // 心跳包發(fā)送間隔,單位:秒

      34        options.userName = id // 用戶名

      35        options.password = token.toCharArray() // 密碼

      36        options.mqttVersion = MqttConnectOptions.MQTT_VERSION_3_1_1;

      37        // 設(shè)置MQTT監(jiān)聽(tīng)

      38        mqttClient?.setCallback(object : MqttCallback {

      39            override fun connectionLost(t: Throwable) {

      40                // 通知鏈接斷開(kāi)

      41                VMLog.d("MQTT 鏈接斷開(kāi) $t")

      42            }

      43

      44            @Throws(Exception::class)

      45            override fun messageArrived(topic: String, message: MqttMessage) {

      46                // 通知收到消息

      47                VMLog.d("MQTT 收到消息:$message")

      48                // 如果未訂閱則直接丟棄

      49                if (!topicList.contains(topic)) return

      50                notifyEvent(topic, String(message.payload))

      51            }

      52

      53            override fun deliveryComplete(token: IMqttDeliveryToken) {}

      54        })

      55        //進(jìn)行連接

      56        mqttClient?.connect(options, null, object : IMqttActionListener {

      57            override fun onSuccess(token: IMqttToken) {

      58                VMLog.d("MQTT 鏈接成功")

      59                // 鏈接成功,循環(huán)訂閱緩存的主題

      60                topicList.forEach { subscribe(it) }

      61            }

      62

      63            override fun onFailure(token: IMqttToken, t: Throwable) {

      64                VMLog.d("MQTT 鏈接失敗 $t")

      65            }

      66        })

      67    }

      68

      69    /**

      70     * 訂閱主題

      71     * @param topic 主題

      72     */

      73    fun subscribe(topic: String) {

      74        if (!topicList.contains(topic)) {

      75            topicList.add(topic)

      76        }

      77        try {

      78            //連接成功后訂閱主題

      79            mqttClient?.subscribe(topic, 0, null, object : IMqttActionListener {

      80                override fun onSuccess(token: IMqttToken) {

      81                    VMLog.d("MQTT 訂閱成功 $topic")

      82                }

      83

      84                override fun onFailure(token: IMqttToken, t: Throwable) {

      85                    VMLog.d("MQTT 訂閱失敗 $topic $t")

      86                }

      87            })

      88        } catch (e: MqttException) {

      89            e.printStackTrace()

      90        }

      91    }

      92

      93    /**

      94     * 取消訂閱

      95     * @param topic 主題

      96     */

      97    fun unsubscribe(topic: String) {

      98        if (topicList.contains(topic)) {

      99            topicList.remove(topic)

      100        }

      101        try {

      102            mqttClient?.unsubscribe(topic)

      103        } catch (e: MqttException) {

      104            e.printStackTrace()

      105        }

      106    }

      107

      108    /**

      109     * 發(fā)送 MQTT 消息

      110     * @param topic 主題

      111     * @param content 內(nèi)容

      112     */

      113    fun sendMsg(topic: String, content: String) {

      114        val msg = MqttMessage()

      115        msg.payload = content.encodeToByteArray() // 設(shè)置消息內(nèi)容

      116        msg.qos = 0 //設(shè)置消息發(fā)送質(zhì)量,可為0,1,2.

      117        // 設(shè)置消息的topic,并發(fā)送。

      118        mqttClient?.publish(topic, msg, null, object : IMqttActionListener {

      119            override fun onSuccess(asyncActionToken: IMqttToken) {

      120                VMLog.d("MQTT 消息發(fā)送成功")

      121            }

      122

      123            override fun onFailure(asyncActionToken: IMqttToken, exception: Throwable) {

      124                VMLog.d("MQTT 消息發(fā)送失敗 ${exception.message}")

      125            }

      126        })

      127    }

      128

      129    /**

      130     * 通知 MQTT 事件

      131     */

      132    private fun notifyEvent(topic: String, data: String) {

      133        LDEventBus.post(topic, data)

      134    }

      135 }

      業(yè)務(wù)交互

      和業(yè)務(wù)相關(guān)的就是在啟動(dòng)APP后,使用后端服務(wù)器返回的鑒權(quán)token信息及連接封裝接口登錄環(huán)信通MQTT服務(wù)器,登錄成功后訂閱主題并監(jiān)聽(tīng)消息。

      1// 請(qǐng)求 token 成功后,調(diào)用MQTTHelper.connect()鏈接 MQTT 服務(wù)器,這里會(huì)同時(shí)傳遞監(jiān)聽(tīng)的主題

      2MQTTHelper.connect(mUser.id, token, MQTTConstants.Topic.newMatchInfo)

      3

      4/**

      5 * 發(fā)送匹配信息

      6 */

      7private fun sendMatchInfo() {

      8    if (selfMatch.user.nickname.isEmpty()) return

      9    // 提交自己的匹配信息到服務(wù)器

      10    mViewModel.submitMatch(selfMatch)

      11    val json = JSONObject()

      12    json.put("content", selfMatch.content)

      13    json.put("emotion", selfMatch.emotion)

      14    json.put("gender", selfMatch.gender)

      15    json.put("type", selfMatch.type)

      16    val jsonUser = JSONObject()

      17    jsonUser.put("avatar", mUser.avatar)

      18    jsonUser.put("id", mUser.id)

      19    jsonUser.put("nickname", mUser.nickname)

      20    jsonUser.put("username", mUser.username)

      21    json.put("user", jsonUser)

      22    MQTTHelper.sendMsg(MQTTConstants.Topic.newMatchInfo, json.toString())

      23}

      24

      25// 監(jiān)聽(tīng)消息這里使用了一個(gè)事件總線進(jìn)行通知,在上邊封裝 MQTTHelper 發(fā)送消息也使用了這個(gè),

      26// 訂閱 MQTT 事件

      27LDEventBus.observe(this, MQTTConstants.Topic.newMatchInfo, String::class.java) {

      28        val match = JsonUtils.fromJson(it, Match::class.java)

      29        // 這里收到匹配信息之后就增加一條彈幕

      30    addBarrage(match)

      31}

      后端服務(wù)實(shí)現(xiàn)

      接下來(lái)介紹后端服務(wù)實(shí)現(xiàn),主要包含以下兩部分:

      配置連接信息:配置環(huán)信MQTT消息云連接信息。

      獲取鑒權(quán)信息:獲取客戶端連接需要的鑒權(quán)信息。

      配置連接信息

      配置部分只需要按照環(huán)信后臺(tái)配置信息進(jìn)行替換就好,配置在config目錄下的config.xxx.json文件內(nèi)

      1/**

      2 * Easemob MQTT 配置 https://console.easemob.com/app/generalizeMsg/overviewService

      3 */

      4config.mqtt = {

      5    host: 'mqtt host', // MQTT 鏈接地址

      6  appId: 'appId', // MQTT AppId

      7  port: [ 1883, 1884, 80, 443 ], // MQTT 端口 1883(mqtt),1884(mqtts),80(ws),443(wss)

      8  restHost: 'https://api.cn1.mqtt.chat/app/8igtc0', // MQTT 服務(wù) API 地址

      9  clientId: 'client id', // 替換環(huán)信后臺(tái) clientId

      10  clientSecret: 'client secret', // 替換環(huán)信后臺(tái) clientSecret

      11};

      獲取鑒權(quán)信息

      這里主要是獲取客戶端連接所需要的鑒權(quán)信息token,為了安全token肯定是要放在服務(wù)器端生成的,廢話不多說(shuō),上代碼:

      1/**

      2 * Create by lzan13 on 2022/3/22

      3 * 描述:MQTT 幫助類

      4 */

      5object MQTTHelper {

      6

      7    private var mqttClient: MqttAndroidClient? = null

      8

      9    // 緩存主題集合

      10    private val topicList = mutableListOf()

      11

      12    /**

      13     * 鏈接MQTT

      14     * @param id 用戶 Id

      15     * @param token 用戶鏈接 MQTT 的 Token

      16     * @param topic 需要訂閱的主題,不為空就會(huì)在連接成功后進(jìn)行訂閱

      17     */

      18    fun connect(id: String, token: String, topic: String = "") {

      19        // 處理訂閱主題

      20        if (topic.isNotEmpty()) topicList.add(topic)

      21

      22        // 拼接鏈接地址

      23        val url = "tcp://${MQTTConstants.mqttHost()}:${MQTTConstants.mqttPort()}"

      24        // 拼接 clientId

      25        val clientId = "${id}@${MQTTConstants.mqttAppId()}"

      26        mqttClient = MqttAndroidClient(VMTools.context, url, clientId)

      27

      28        //連接參數(shù)

      29        val options = MqttConnectOptions()

      30        options.isAutomaticReconnect = true //設(shè)置自動(dòng)重連

      31        options.isCleanSession = true // 緩存

      32        options.connectionTimeout = CConstants.timeMinute.toInt() // 設(shè)置超時(shí)時(shí)間,單位:秒

      33        options.keepAliveInterval = CConstants.timeMinute.toInt() // 心跳包發(fā)送間隔,單位:秒

      34        options.userName = id // 用戶名

      35        options.password = token.toCharArray() // 密碼

      36        options.mqttVersion = MqttConnectOptions.MQTT_VERSION_3_1_1;

      37        // 設(shè)置MQTT監(jiān)聽(tīng)

      38        mqttClient?.setCallback(object : MqttCallback {

      39            override fun connectionLost(t: Throwable) {

      40                // 通知鏈接斷開(kāi)

      41                VMLog.d("MQTT 鏈接斷開(kāi) $t")

      42            }

      43

      44            @Throws(Exception::class)

      45            override fun messageArrived(topic: String, message: MqttMessage) {

      46                // 通知收到消息

      47                VMLog.d("MQTT 收到消息:$message")

      48                // 如果未訂閱則直接丟棄

      49                if (!topicList.contains(topic)) return

      50                notifyEvent(topic, String(message.payload))

      51            }

      52

      53            override fun deliveryComplete(token: IMqttDeliveryToken) {}

      54        })

      55        //進(jìn)行連接

      56        mqttClient?.connect(options, null, object : IMqttActionListener {

      57            override fun onSuccess(token: IMqttToken) {

      58                VMLog.d("MQTT 鏈接成功")

      59                // 鏈接成功,循環(huán)訂閱緩存的主題

      60                topicList.forEach { subscribe(it) }

      61            }

      62

      63            override fun onFailure(token: IMqttToken, t: Throwable) {

      64                VMLog.d("MQTT 鏈接失敗 $t")

      65            }

      66        })

      67    }

      68

      69    /**

      70     * 訂閱主題

      71     * @param topic 主題

      72     */

      73    fun subscribe(topic: String) {

      74        if (!topicList.contains(topic)) {

      75            topicList.add(topic)

      76        }

      77        try {

      78            //連接成功后訂閱主題

      79            mqttClient?.subscribe(topic, 0, null, object : IMqttActionListener {

      80                override fun onSuccess(token: IMqttToken) {

      81                    VMLog.d("MQTT 訂閱成功 $topic")

      82                }

      83

      84                override fun onFailure(token: IMqttToken, t: Throwable) {

      85                    VMLog.d("MQTT 訂閱失敗 $topic $t")

      86                }

      87            })

      88        } catch (e: MqttException) {

      89            e.printStackTrace()

      90        }

      91    }

      92

      93    /**

      94     * 取消訂閱

      95     * @param topic 主題

      96     */

      97    fun unsubscribe(topic: String) {

      98        if (topicList.contains(topic)) {

      99            topicList.remove(topic)

      100        }

      101        try {

      102            mqttClient?.unsubscribe(topic)

      103        } catch (e: MqttException) {

      104            e.printStackTrace()

      105        }

      106    }

      107

      108    /**

      109     * 發(fā)送 MQTT 消息

      110     * @param topic 主題

      111     * @param content 內(nèi)容

      112     */

      113    fun sendMsg(topic: String, content: String) {

      114        val msg = MqttMessage()

      115        msg.payload = content.encodeToByteArray() // 設(shè)置消息內(nèi)容

      116        msg.qos = 0 //設(shè)置消息發(fā)送質(zhì)量,可為0,1,2.

      117        // 設(shè)置消息的topic,并發(fā)送。

      118        mqttClient?.publish(topic, msg, null, object : IMqttActionListener {

      119            override fun onSuccess(asyncActionToken: IMqttToken) {

      120                VMLog.d("MQTT 消息發(fā)送成功")

      121            }

      122

      123            override fun onFailure(asyncActionToken: IMqttToken, exception: Throwable) {

      124                VMLog.d("MQTT 消息發(fā)送失敗 ${exception.message}")

      125            }

      126        })

      127    }

      128

      129    /**

      130     * 通知 MQTT 事件

      131     */

      132    private fun notifyEvent(topic: String, data: String) {

      133        LDEventBus.post(topic, data)

      134    }

      135}

      源碼地址

      核心代碼就這么多,不超過(guò)500行,這里沒(méi)有直接調(diào)用環(huán)信歷史消息接口獲取消息存儲(chǔ)記錄,后續(xù)可以在進(jìn)行改良,簡(jiǎn)化實(shí)現(xiàn)流程。源碼鏈接附上,配合使用效果更佳。

      服務(wù)端github源碼:

      https://github.com/lzan13/vmtemplateserver

      客戶端github源碼:

      https://gitee.com/lzan13/VMTemplateAndroid

      寫在最后

      MQTT協(xié)議資源占用小,并發(fā)連接高,集成簡(jiǎn)單,特別適用于高頻數(shù)據(jù)交互場(chǎng)景,比如:游戲的世界廣場(chǎng)、視頻平臺(tái)彈幕等等等等,歡迎各位小伙伴集思廣益,基于MQTT服務(wù)實(shí)現(xiàn)更多的業(yè)務(wù)場(chǎng)景,享受技術(shù)帶來(lái)的便利與快樂(lè)。

      文章內(nèi)容僅供閱讀,不構(gòu)成投資建議,請(qǐng)謹(jǐn)慎對(duì)待。投資者據(jù)此操作,風(fēng)險(xiǎn)自擔(dān)。

    [No. X016-1]
    分享到微信

    即時(shí)

    TCL實(shí)業(yè)榮獲IFA2024多項(xiàng)大獎(jiǎng),展示全球科技創(chuàng)新力量

    近日,德國(guó)柏林國(guó)際電子消費(fèi)品展覽會(huì)(IFA2024)隆重舉辦。憑借在核心技術(shù)、產(chǎn)品設(shè)計(jì)及應(yīng)用方面的創(chuàng)新變革,全球領(lǐng)先的智能終端企業(yè)TCL實(shí)業(yè)成功斬獲兩項(xiàng)“IFA全球產(chǎn)品設(shè)計(jì)創(chuàng)新大獎(jiǎng)”金獎(jiǎng),有力證明了其在全球市場(chǎng)的強(qiáng)大影響力。

    新聞

    敢闖技術(shù)無(wú)人區(qū) TCL實(shí)業(yè)斬獲多項(xiàng)AWE 2024艾普蘭獎(jiǎng)

    近日,中國(guó)家電及消費(fèi)電子博覽會(huì)(AWE 2024)隆重開(kāi)幕。全球領(lǐng)先的智能終端企業(yè)TCL實(shí)業(yè)攜多款創(chuàng)新技術(shù)和新品亮相,以敢為精神勇闖技術(shù)無(wú)人區(qū),斬獲四項(xiàng)AWE 2024艾普蘭大獎(jiǎng)。

    企業(yè)IT

    重慶創(chuàng)新公積金應(yīng)用,“區(qū)塊鏈+政務(wù)服務(wù)”顯成效

    “以前都要去窗口辦,一套流程下來(lái)都要半個(gè)月了,現(xiàn)在方便多了!”打開(kāi)“重慶公積金”微信小程序,按照提示流程提交相關(guān)材料,僅幾秒鐘,重慶市民曾某的賬戶就打進(jìn)了21600元。

    3C消費(fèi)

    “純臻4K 視界煥新”——愛(ài)普生4K 3LCD 激光工程投影

    2024年3月12日,由愛(ài)普生舉辦的主題為“純臻4K 視界煥新”新品發(fā)布會(huì)在上海盛大舉行。

    研究

    2024全球開(kāi)發(fā)者先鋒大會(huì)即將開(kāi)幕

    由世界人工智能大會(huì)組委會(huì)、上海市經(jīng)信委、徐匯區(qū)政府、臨港新片區(qū)管委會(huì)共同指導(dǎo),由上海市人工智能行業(yè)協(xié)會(huì)聯(lián)合上海人工智能實(shí)驗(yàn)室、上海臨港經(jīng)濟(jì)發(fā)展(集團(tuán))有限公司、開(kāi)放原子開(kāi)源基金會(huì)主辦的“2024全球開(kāi)發(fā)者先鋒大會(huì)”,將于2024年3月23日至24日舉辦。