跳转至

sms

作者:王城钧

一、概述

sms 库提供了短信相关功能,包括异步发送短信、同步发送短信、设置新短信回调函数、设置长短信自动合并模式以及清除长短信缓存的功能

1、对于电信卡来说,SMS 短信功能跟核心库 CC(VoLTE 通话)是伴生关系,只有支持 CC 核心库的固件才支持电信卡的 SMS 短信功能;

2、对于移动/联通卡来说,SMS 短信功能合宙所有全网通 4G 模组都默认支持;

3、对于某些只支持单一运营商的型号,比如只支持移动运营商的 Air700ECH/Air700ECT,则相应的也只支持移动卡的 SMS 短信功能;

4、有些流量卡可能没有开通 SMS 短信功能,请咨询卡商或运营商确认,无法确认时建议用自己的手机卡测试确认;

5、再次提醒!由于合宙二次开发型号模组支持多种固件版本,使用电信卡 SMS 短信功能时请务必选择同时支持 CC(VoLTE 通话)的固件版本;

二、核心示例

1、核心示例是指:使用本库文件提供的核心 API,开发的基础业务逻辑的演示代码;

2、核心示例的作用是:帮助开发者快速理解如何使用本库,所以核心示例的逻辑都比较简单;

3、更加完整和详细的 demo,请参考 LuatOS 仓库 中各个产品目录下的 demo/sms

-- LuaTools需要PROJECT和VERSION这两个信息
PROJECT = "smsdemo"
VERSION = "001.000.001"

log.info("main", PROJECT, VERSION)


if wdt then
    --添加硬狗防止程序卡死,在支持的设备上启用这个功能
    wdt.init(9000)--初始化watchdog设置为9s
    sys.timerLoopStart(wdt.feed, 3000)--3s喂一次狗
end
log.info("main", "sms demo")

-- 辅助发送http请求, 因为http库需要在task里运行
function http_post(url, headers, body)
    local function http()
        local code, headers, body = http.request("POST", url, headers, body).wait()
        log.info("resp", code)
    end
    sys.taskInit(http)
end

function sms_handler(num, txt)
    -- num 手机号码
    -- txt 文本内容
    log.info("sms", num, txt, txt:toHex())

    -- http演示1, 发json
    local body = json.encode({phone=num, txt=txt})
    local headers = {}
    headers["Content-Type"] = "application/json"
    log.info("json", body)
    http_post("http://www.luatos.com/api/sms/blackhole", headers, body)
    -- http演示2, 发表单的
    headers = {}
    headers["Content-Type"] = "application/x-www-form-urlencoded"
    local body = string.format("phone=%s&txt=%s", num:urlEncode(), txt:urlEncode())
    log.info("params", body)
    http_post("http://www.luatos.com/api/sms/blackhole", headers, body)
    -- http演示3, 不需要headers,直接发
    http_post("http://www.luatos.com/api/sms/blackhole", nil, num .. "," .. txt)
    -- 如需发送到钉钉, 参考 demo/dingding
    -- 如需发送到飞书, 参考 demo/feishu
end

--------------------------------------------------------------------
-- 接收短信, 支持多种方式, 选一种就可以了
-- 1. 设置回调函数
--sms.setNewSmsCb(sms_handler)
-- 2. 订阅系统消息
--sys.subscribe("SMS_INC", sms_handler)
-- 3. 在task里等着
local function sms_sub()
    while 1 do
        local ret, num, txt = sys.waitUntil("SMS_INC", 300000)
        if num then
            -- 方案1, 交给自定义函数处理
            sms_handler(num, txt)
            -- 方案2, 因为这里是task内, 可以直接调用http.request
            -- local body = json.encode({phone=num, txt=txt})
            -- local headers = {}
            -- headers["Content-Type"] = "application/json"
            -- log.info("json", body)
            -- local code, headers, body = http.request("POST", "http://www.luatos.com/api/sms/blackhole", headers, body).wait()
            -- log.info("resp", code)
        end
    end
end
sys.taskInit(sms_sub)

-------------------------------------------------------------------
-- 发送短信, 直接调用sms.send就行, 是不是task无所谓
local function sms_send()
     sys.wait(10000)
    -- 中移动卡查短信
     sms.send("+8610086", "301")
    -- 联通卡查话费
    -- sms.send("10010", "101")
end
sys.taskInit(sms_send)



-- 用户代码已结束---------------------------------------------
-- 结尾总是这一句
sys.run()
-- sys.run()之后后面不要加任何语句!!!!!

三、常量详解

核心库常量,顾名思义是由合宙 LuatOS 内核固件中定义的、不可重新赋值或修改的固定值,在脚本代码中不需要声明,可直接调用;

每个常量对应的常量取值仅做日志打印时查询使用,不要将这个常量取值用做具体的业务逻辑判断,因为LuatOS内核固件可能会变更每个常量对应的常量取值;

如果用做具体的业务逻辑判断,一旦常量取值发生改变,业务逻辑就会出错;

"SMS_INC"

消息类型:string
消息含义:表示收到短信内容
注意事项:普通短信(非长短信):
         每收到一条短信,立即执行回调函数。
         长短信(多条短信组成的完整消息):
         必须所有短信片段接收完成后才会执行一次回调,不会每收到一条片段就触发回调。
参数示例:
-- 接收短信, 支持多种方式, 选一种就可以了
-- 1. 设置回调函数
local function handleNewSms(phone, sms)  
    log.info("sms", phone, sms)  
end   
sms.setNewSmsCb(handleNewSms)

-- 2. 订阅系统消息
local function handleSmsInc(phone, sms)  
    log.info("sms", phone, sms)  
end  
sys.subscribe("SMS_INC", handleSmsInc)

"SMS_SEND_RESULT"

消息类型:string
消息含义:表示短信发送操作的最终结果通知,包含发送成功或失败的状态信息。
注意事项:普通短信(非长短信):
         每发送一条短信,当网络返回发送结果后立即触发一次该消息。
         由于 sms.send() 是异步操作,其返回值仅表示发送请求是否成功提交,而非实际发送结果。
         长短信(多条短信组成的完整消息):
         仅在所有短信片段全部发送完成后才会触发一次该消息。
         不会对每个短信片段单独触发消息,确保应用层只收到一次完整的发送结果。
         对于长短信,建议使用 sms.sendLong().wait() 方式获取发送结果。
参数示例:-- 发送短信并等待结果
local function sendSmsWithResult()
    local result = sms.sendLong("+8613416121234", "这是一条测试短信").wait()
    if result then
        log.info("sms", "短信发送成功")
    else
        log.info("sms", "短信发送失败")
    end
end

sys.taskInit(sendSmsWithResult)

四、函数详解

sms.send(phone, msg, auto_phone_fix)

功能

异步发送短信,通过返回值确认任务启动状态,底层"SMS_SEND_RESULT"消息获取最终发送结果。

参数

phone

参数含义:表示电话号码;
数据类型:string
取值范围:暂无;
是否必选:必须传入此参数;
注意事项:暂无;
参数示例:"13188888888"

msg

参数含义:短信内容,编码格式为UTF-8的字符串;
数据类型:string
取值范围:暂无;
是否必选:必须传入此参数;
注意事项:单条短信最大为140字节,一个英文算一个字节,一个中文算2个字节;
         sendLong的主要差异为异步发送模式
参数示例:"101"

auto_phone_fix

参数含义:用于控制是否自动修正电话号码格式,
         auto_phone_fix=true时(默认值)
         系统会对电话号码进行智能处理,具体规则如下:
         1.如果电话号码以'+'开头(例如"+8613416121234"),会自动移除'+'号,保留后面的部分
         2.如果电话号码不以'86'开头(中国国家代码),会自动在号码前面添加'86'
         3.如果电话号码已经以'86'开头,则保持不变
         auto_phone_fix=false时
         系统会直接使用用户传入的电话号码,不做任何自动处理和格式调整
         -- 自动处理模式
         -- 输入:sms.send("+8613416121234", "Hello",true) 
         -- auto_phone_fix=true(默认)
         -- 实际发送的号码:"8613416121234"(自动去掉'+'号)

         -- 禁用自动处理
         -- 输入:sms.send("+8613416121234", "Hello", false)
         -- 实际发送的号码:"+8613416121234"(保持原样)
         默认true
数据类型:boolean
取值范围:true/false
是否必选:可选传入此参数;
注意事项:暂无;
参数示例:true

返回值

local result = sms.send(phone, msg, auto_phone_fix)

result

含义说明短信发送结果
         sms.send 的同步结果仅表示任务启动成功
         最终发送状态需通过异步事件 "SMS_SEND_RESULT" 获取
数据类型boolean
取值范围true或者false
注意事项暂无
返回示例true

示例

sms.send("10010", "101")

sms.sendLong(phone, msg, auto_phone_fix).wait()

功能

同步发送短信,只可以在 task 中运行,支持长级联短信;

参数

phone

参数含义:表示电话号码;
数据类型:string
取值范围:暂无;
是否必选:必须传入此参数;
注意事项:暂无;
参数示例:"13188888888"

msg

参数含义:短信内容,编码格式编码格式为UTF-8字符串;
数据类型:string
取值范围:暂无;
是否必选:必须传入此参数;
注意事项:支持长短信,长短信单分片大小最大134字节,
         最大分片数量128片,
         一个英文算一个字节,一个中文算2个字节,
          sms.send 相比,核心差异在于同步发送模式
         如果超过最长限制,
         会出现下列情况:
         1. 直接返回失败,表示发送任务未启动。
         2. 自动截断并发送部分内容
         3. 触发模块内部错误调用后无返回(卡死)
            或抛出异常(如内存不足、缓冲区溢出)
参数示例:"祝你天天开心!"

auto_phone_fix

参数含义:用于控制是否自动修正电话号码格式,
         auto_phone_fix=true时(默认值)
         系统会对电话号码进行智能处理,具体规则如下:
         1.如果电话号码以'+'开头(例如"+8613416121234"),会自动移除'+'号,保留后面的部分
         2.如果电话号码不以'86'开头(中国国家代码),会自动在号码前面添加'86'
         3.如果电话号码已经以'86'开头,则保持不变
         auto_phone_fix=false时
         系统会直接使用用户传入的电话号码,不做任何自动处理和格式调整
         -- 自动处理模式
         -- 输入:sms.send("+8613416121234", "Hello",true) 
         -- auto_phone_fix=true(默认)
         -- 实际发送的号码:"8613416121234"(自动去掉'+'号)

         -- 禁用自动处理
         -- 输入:sms.send("+8613416121234", "Hello", false)
         -- 实际发送的号码:"+8613416121234"(保持原样)
         默认true
数据类型:boolean
取值范围:true/false
是否必选:可选传入此参数;
注意事项:暂无;
参数示例:true

返回值

local result = sms.sendLong(phone, msg, auto_phone_fix).wait()

result

含义说明:短信发送结果;
数据类型:boolean
取值范围:true或者false
注意事项:暂无;
返回示例:true

示例

sms.sendLong("10010", "101").wait()

sms.setNewSmsCb(func)

功能

设置接收到新短信的回调函数,

  1. 普通短信(非长短信):每收到一条短信,立即执行回调函数。
  2. 长短信(多条短信组成的完整消息):必须所有短信片段接收完成后才会执行一次回调,不会每收到一条片段就触发回调。

参数

func

参数含义:接收到新短信时触发的回调函数,支持处理普通短信与长短信两种模式
         普通短信:每收到一条立即执行,参数为(num, txt, metas)  
         长短信:所有分段接收完成后执行一次,metas包含完整分段元数据
         回调函数格式为:
         function callbacknum, txt, metas
         -- num: string类型,表示电话号码
         -- txt:string类型,表示发送的文本信息
         -- metas(短信):year(年)、mon(月)、 day(日)、hour(时)、min(分)、sec(秒)、tz(时区)
         -- metas(短信):refNum:长短信的参考编号
- seqNum :当前短信分片的序号
- maxNum :长短信的总分片数
数据类型:function
取值范围:暂无;
是否必选:必须传入此参数;
注意事项:暂无;
参数示例:local function smscb(num, txt, metas)
             log.info("sms", num, txt, metas and json.encode(metas) or "")
         end
         sms.setNewSmsCb(smscb)
         -- 普通短信示例:
         -- local function smscb1("+8613800138000","+8613800138000",
         -- {year=2025,mon=10,day=11,hour=15,min=30,sec=45,tz=480})
         -- sms.setNewSmsCb(smscb1) 
         -- 长短信示例: 
         -- local function smscb2("+8613900139000", txt="这是一条长短信合并后的完整内容",
         -- metas={refNum=123,seqNum=3,maxNum=3,year=2025,mon=10,day=11,hour=15,min=32,sec=00,tz=480})
         -- sms.setNewSmsCb(smscb2)

返回值

nil

示例

local function smscb(num, txt, metas)
    -- num 手机号码
    -- txt 文本内容
    -- metas 短信的元数据
    -- 普通短信的metas结构:
    -- {
    --  refNum = nil,    -- 无长短信编号
    --  seqNum = 1,      -- 固定为1
    --  maxNum = 1,      -- 固定为1
    -- }
    -- 长短信合并后的metas结构:
    -- {
    -- refNum = 123,    -- 长短信唯一ID
    -- seqNum = 1,      -- 当前为第1段
    -- maxNum = 3,      -- 共3段
    -- year = 2025, mon = 10, day = 11, 
    -- hour = 15, min = 30, sec = 45, 
    -- tz = 480         -- +8:00时区
     -- }
    -- 时间戳字段同上
    -- 注意, 如果开启了长短信自动合并功能,
    -- 长短信会自动合并成一条txt
    log.info("sms", num, txt, metas and json.encode(metas) or "")
end)
sms.setNewSmsCb(smscb)

sms.autoLong(mode)

功能

设置长短信的自动合并功能

参数

mode

参数含义:是否自动合并,true为自动合并,为默认值;
数据类型:boolean
取值范围:暂无;
是否必选:可选传入此参数;
注意事项:暂无;
参数示例:true

返回值

local result = sms.autoLong(true)

含义说明:设置长短信的自动合并功能结果;
数据类型:boolean
取值范围:true或者false
注意事项:暂无;
返回示例:true

示例

sms.autoLong(false)

sms.clearLong()

功能

清除长短信缓存

使用场景如下:

  1. 长短信分片未完全接收导致缓存残留
  2. 缓存池溢出风险
  3. 内存资源紧张
  4. 异常状态重置

参数

nil

返回值

local num = sms.clearLong()

num

含义说明:清理掉的片段数量;
数据类型:number
取值范围:暂无;
注意事项:暂无;
返回示例:1

示例

sms.clearLong()

五、产品支持说明

目前合宙主流模组都支持 sms 核心库。