用 LEDE 实现短信验证码转发

前段时间貌似是因为电信网络维护停止了 CDMA 的本网漫游,需要漫游到 WCDMA。奈何短信机是台红米 1S,不支持 WCDMA,导致收不到各种验证码。于是打算使用 3G 模块接收短信,并转发到 Telegram。

经过一番调查后发现:

  1. 日本早在 2012 年 5 月 31 日全面停止了 2G 网络的服务,于是 GSM 不可行。
  2. 打电话给电信回复说:CDMA 维护,恢复时间不定,请使用 WCDMA 网络。这说明异网漫游是正常的。
  3. DoCoMo 的 WCDMA 频段是 Band 1,6,9,19。

然后去日拍翻了下,刚好有一款符合要求:


image.png
华为 E173U

标准 AT 指令操作,支持收发短信。

测试入网

正常入网

正常入网,接着测试 AT 指令

测试 AT 指令

一切正常。

配置 LEDE

首先需要安装 USB 驱动

opkg install kmod-usb-serial kmod-usb-serial-wwan kmod-usb-serial-option usb-modeswitch

主要就是这些,可能还有其他需要安装的我没有列出来,具体请参考 Use 3g/UMTS USB Dongle for WAN connection

之后就是配置短信服务,这里用到的是 smstools3,所以

opkg install smstools3

接着需要配置 smstool3,配置文件在 /etc/smsd.conf,修改完之后应该是这样:

#
# Description: Main configuration file for the smsd
#

devices = GSM1
incoming = /var/spool/sms/incoming
outgoing = /var/spool/sms/outgoing
checked = /var/spool/sms/checked
failed = /var/spool/sms/failed
sent = /var/spool/sms/sent
receive_before_send = no
autosplit = 3
incoming_utf8 = yes

# 轮询短信间隔时间
delaytime = 1

[GSM1]
# 将短信保存在上网卡中(更快,不支持的话请使用 SM 模式)
init = AT+CPMS="ME","ME","ME"

# 将短信保存在 USIM 卡中
# init = AT+CPMS="SM","SM","SM"

device = /dev/ttyUSB0
incoming = yes

# 如果 USIM 卡有设置 pin 码需要设置这行来解锁
# pin = 0000

# 波特率,一般都是 115200,不对的话请自行修改
baudrate = 115200

# 如果检测得到信息但是无法读取需要修改这里的读取模式
check_memory_method = 2

report_device_details = yes
signal_quality_ber_ignore = yes
check_network = no

如果你的上网卡的串口路径不是 /dev/ttyUSB0 请查找后自行修改:

ls /dev | grep tty
...
ttyUSB0
ttyUSB1
ttyUSB2
...

启动服务

/etc/init.d/smstools3 restart

这样一来就能正常收到短信了。
顺便一提,E173U 的指示灯:

  • 闪绿灯:初始化正常,正在搜索网络
  • 闪蓝灯:正常入网

不出意外的话,在配置好上网卡的软件包后插上上网卡就能看到蓝灯闪烁,代表正常入网。

测试 smstools

刚刚配置好了 smstools 但是不知道是否工作正常,于是查看日志:

2017-06-08 03:25:34,7, smsd: Done: startup_check (shell), execution time 0 sec., status: 0 (0)
2017-06-08 03:25:34,4, smsd: File mode creation mask: 022 (0644, rw-r--r--).
2017-06-08 03:25:34,5, smsd: Outgoing file checker has started. PID: 9684.
2017-06-08 03:25:34,7, smsd: All PID's: 9684,9686
2017-06-08 03:25:34,5, GSM1: Modem handler 0 has started. PID: 9686.
2017-06-08 03:25:34,5, GSM1: Using check_memory_method 1: CPMS is used.
2017-06-08 03:25:34,6, GSM1: Checking device for incoming SMS
2017-06-08 03:25:34,6, GSM1: Checking if modem is ready
2017-06-08 03:25:34,7, GSM1: -> AT
2017-06-08 03:25:34,7, GSM1: Command is sent, waiting for the answer
2017-06-08 03:25:35,7, GSM1: <- OK
2017-06-08 03:25:35,6, GSM1: Pre-initializing modem
2017-06-08 03:25:35,7, GSM1: -> ATE0+CMEE=1;+CREG=2
2017-06-08 03:25:35,7, GSM1: Command is sent, waiting for the answer
2017-06-08 03:25:35,7, GSM1: <- OK
2017-06-08 03:25:35,6, GSM1: Checking if modem needs PIN
2017-06-08 03:25:35,7, GSM1: -> AT+CPIN?
2017-06-08 03:25:35,7, GSM1: Command is sent, waiting for the answer
2017-06-08 03:25:36,7, GSM1: <- +CPIN: READY OK
2017-06-08 03:25:36,6, GSM1: Initializing modem
2017-06-08 03:25:36,7, GSM1: -> AT^CURC=0
2017-06-08 03:25:36,7, GSM1: Command is sent, waiting for the answer
2017-06-08 03:25:36,7, GSM1: <- OK
2017-06-08 03:25:36,7, GSM1: -> AT+CSQ
2017-06-08 03:25:36,7, GSM1: Command is sent, waiting for the answer
2017-06-08 03:25:37,7, GSM1: <- +CSQ: 12,99 OK
2017-06-08 03:25:37,6, GSM1: Signal Strength Indicator: (12,99) -89 dBm (Workable)
2017-06-08 03:25:37,6, GSM1: Checking if Modem is registered to the network
2017-06-08 03:25:37,7, GSM1: -> AT+CREG?
2017-06-08 03:25:37,7, GSM1: Command is sent, waiting for the answer
2017-06-08 03:25:37,7, GSM1: <- +CREG: 2,5, 66, C018 OK
2017-06-08 03:25:37,6, GSM1: Modem is registered to a roaming partner network
2017-06-08 03:25:37,6, GSM1: Location area code: 66, Cell ID: C018
2017-06-08 03:25:37,7, GSM1: -> AT+CSQ
2017-06-08 03:25:37,7, GSM1: Command is sent, waiting for the answer
2017-06-08 03:25:38,7, GSM1: <- +CSQ: 13,99 OK
2017-06-08 03:25:38,6, GSM1: Signal Strength Indicator: (13,99) -87 dBm (Workable)
2017-06-08 03:25:38,6, GSM1: Selecting PDU mode
2017-06-08 03:25:38,7, GSM1: -> AT+CMGF=0
2017-06-08 03:25:38,7, GSM1: Command is sent, waiting for the answer
2017-06-08 03:25:38,7, GSM1: <- OK
2017-06-08 03:25:38,7, GSM1: -> AT+CIMI
2017-06-08 03:25:38,7, GSM1: Command is sent, waiting for the answer
2017-06-08 03:25:39,7, GSM1: <- 204046003816003 OK
2017-06-08 03:25:39,7, GSM1: -> AT+CGSN
2017-06-08 03:25:39,7, GSM1: Command is sent, waiting for the answer
2017-06-08 03:25:39,7, GSM1: <- 352216049835909 OK
2017-06-08 03:25:39,5, GSM1: CGSN: 352216049835909
2017-06-08 03:25:39,5, GSM1: IMSI: 204046003816003
2017-06-08 03:25:39,6, GSM1: Checking if reading of messages is supported
2017-06-08 03:25:39,7, GSM1: -> AT+CPMS?
2017-06-08 03:25:39,7, GSM1: Command is sent, waiting for the answer
2017-06-08 03:25:40,7, GSM1: <- +CPMS: "SM",1,40,"SM",1,40,"SM",1,40 OK
2017-06-08 03:25:40,7, GSM1: ## Start of device details
2017-06-08 03:25:40,7, GSM1: # Manufacturer identification:
2017-06-08 03:25:40,7, GSM1: -> AT+CGMI
2017-06-08 03:25:40,7, GSM1: <- huawei
OK
2017-06-08 03:25:40,7, GSM1: # Model identification:
2017-06-08 03:25:40,7, GSM1: -> AT+CGMM
2017-06-08 03:25:41,7, GSM1: <- E173
OK
2017-06-08 03:25:41,7, GSM1: # Revision identification:
2017-06-08 03:25:41,7, GSM1: -> AT+CGMR
2017-06-08 03:25:41,7, GSM1: <- 11.126.83.00.00
OK
2017-06-08 03:25:41,7, GSM1: # New message indications, list of supported modes:
2017-06-08 03:25:41,7, GSM1: -> AT+CNMI=?
2017-06-08 03:25:42,7, GSM1: <- +CNMI: (0,1,2),(0,1,2,3),(0,2),(0,1,2),(0,1)
OK
2017-06-08 03:25:42,7, GSM1: # New message indications, current settings:
2017-06-08 03:25:42,7, GSM1: -> AT+CNMI?
2017-06-08 03:25:42,7, GSM1: <- +CNMI: 0,0,0,0,0
OK
2017-06-08 03:25:42,7, GSM1: # Preferred message storage, list of supported mem's:
2017-06-08 03:25:42,7, GSM1: -> AT+CPMS=?
2017-06-08 03:25:43,7, GSM1: <- +CPMS: ("ME","MT","SM","SR"),("ME","MT","SM","SR"),("ME","MT","SM","SR")
OK
2017-06-08 03:25:43,7, GSM1: # Phonebook storage, available mem's:
2017-06-08 03:25:43,7, GSM1: -> AT+CPBS=?
2017-06-08 03:25:43,7, GSM1: <- +CPBS: ("SM","EN","ON")
OK
2017-06-08 03:25:43,7, GSM1: # List messages, list of supported stat's:
2017-06-08 03:25:43,7, GSM1: -> AT+CMGL=?
2017-06-08 03:25:44,7, GSM1: <- +CMGL: (0-4)

没毛病。

发个短信试试

2017-06-08 03:28:34,6, GSM1: Checking memory size
2017-06-08 03:28:34,7, GSM1: -> AT+CPMS?
2017-06-08 03:28:34,7, GSM1: Command is sent, waiting for the answer
2017-06-08 03:28:34,7, GSM1: <- +CPMS: "SM",2,40,"SM",2,40,"SM",2,40 OK
2017-06-08 03:28:34,6, GSM1: Used memory is 2 of 40
2017-06-08 03:28:34,6, GSM1: Trying to get stored message 1
2017-06-08 03:28:34,7, GSM1: -> AT+CMGR=1
2017-06-08 03:28:34,7, GSM1: Command is sent, waiting for the answer
2017-06-08 03:28:35,7, GSM1: <- +CMGR: 0,,146 07911356044902000405A15955F5000871608020820023829A8C8BC17801003300370034003000340039FF0C60A86B63572875284E007F51901A767B5F55FF0C5982975E672C4EBA64CD4F5CFF0C8BF780547CFB0039003500350035003530028BF752FF57284EFB4F5577ED4FE1621690AE4EF694FE63A57684987597624E2D8F9351659A8C8BC17801FF010020005B62DB554694F6884C005D OK
2017-06-08 03:28:35,5, GSM1: SMS received, From: 95555
2017-06-08 03:28:35,6, GSM1: Wrote an incoming message file: /var/spool/sms/incoming/GSM1.IgkBhN
2017-06-08 03:28:35,7, GSM1: Running eventhandler: /root/sms RECEIVED /var/spool/sms/incoming/GSM1.IgkBhN
2017-06-08 03:28:36,7, GSM1: Done: eventhandler, execution time 1 sec., status: 0 (0)

没毛病。

查看 incoming 文件夹中的文件 /var/spool/sms/incoming/GSM1.IgkBhN

From: 95555
From_TOA: A1 national, ISDN/telephone
From_SMSC: 316540942000
Sent: 17-06-08 02:28:00
Received: 17-06-08 03:28:35
Subject: GSM1
Modem: GSM1
IMSI: 204046003816003
Report: no
Alphabet: UCS2
Length: 65

▒▒▒▒xxxxxxx▒
`▒kcW(u(Q▒v{_U▒
Y▒▒^g,N▒d▒O\▒
▒▒T|▒955550▒▒R▒W(N▒OUw▒O▒b▒▒N▒▒c▒v▒▒u▒bN-▒▒Qe▒▒▒▒x▒ [b▒UF▒▒L]

这里的正文显示为乱码。上面也有提到 Alphabet: UCS2,于是使用 iconv 转换。

opkg install iconv

这里需要注意的是,需要去掉前面的 ASCII 部分,不然会变成乱码。

sed -i '1,12d' /var/spool/sms/incoming/GSM1.IgkBhN
iconv -f UTF-16BE -t UTF-8 < /var/spool/sms/incoming/GSM1.IgkBhN
验证码xxxxxx,您正在用一网通登录,如非本人操作,请联系95555。请勿在任何短信或邮件链接的页面中输入验证码! [招商银行]

于是我们就得到了完整的短信。

转发短信

因为日常使用 Telegram 比较多,自然就想到了 Telegram Bot。

找 BotFather 要一个 Bot

BotFather

找 @get_id_bot 这个 Bot 拿到自己的 chat id

@get_id_bot

然后我们需要一个 hook,在收到短信的时候执行 shell,所幸 smstools3 有这样的 hook 给我们直接用。

编辑 /etc/smsd.conf
[GSM1] 的末尾加上:

eventhandler = /root/sms

这样在收到短信时就会调用这个 shell 并传递两个参数:

  1. 事件类型,比如收到短信是 RECIVED
  2. 短信存档路径

于是我们的 /root/sms 如下:

#!/bin/sh

TMPFILE1=$(cat /dev/urandom | tr -cd 'a-f0-9' | head -c 8)
TMPFILE2=$(cat /dev/urandom | tr -cd 'a-f0-9' | head -c 8)

cat $2 > $TMPFILE2

awk 'NR==1 || NR==4 || NR==5' $TMPFILE2 >> $TMPFILE1
sed -i '1,12d' $TMPFILE2
iconv -f UTF-16BE -t UTF-8 < $TMPFILE2 >> $TMPFILE1


CONTENT=`cat $TMPFILE1`

echo SMSD alarm: $1 $2 >> /root/sms.txt
curl -i -X POST \
  -F "chat_id=<chat_id>" \
  -F "text=${CONTENT}" \
  "https://api.telegram.org/bot<apikey>/sendMessage"

rm $TMPFILE1 $TMPFILE2

记得加上执行权限

chmod +x /root/sms

其中 chat_id 为你自己的 chat id,并替换网址中的 apikey。
最后记得在 Telegram 中找到你的 Bot 发送 /start 不然 Bot 没有权限给你发送消息。

升级 curl

测试脚本后发现并不能正常运行,原因是 LEDE 17.01.1 的 curl 有一些 bug 尚未修复。

于是我们需要升级 curl 和 libcurl 到 snapshot 的版本。

https://downloads.lede-project.org/snapshots/packages/
在这里找到路由器对应的指令集,进入 base 文件夹下载 curl 和 libcurl 两个软件包。

比如 ar71xx 的是这两个:
curl
libcurl

使用 opkg 安装:

wget https://downloads.lede-project.org/snapshots/packages/mips_24kc/base/curl_7.54.0-1_mips_24kc.ipk
wget https://downloads.lede-project.org/snapshots/packages/mips_24kc/base/libcurl_7.54.0-1_mips_24kc.ipk
opkg remove curl
opkg remove libcurl
opkg install libcurl_7.54.0-1_mips_24kc.ipk
opkg install curl_7.54.0-1_mips_24kc.ipk

这样 curl 就能正常工作了。

测试 Bot

重启 smstools3

/etc/init.d/smstools3 restart

发送短信并查看日志

2017-06-08 04:35:01,6, GSM1: Checking memory size
2017-06-08 04:35:02,7, GSM1: -> AT+CPMS?
2017-06-08 04:35:02,7, GSM1: Command is sent, waiting for the answer
2017-06-08 04:35:02,7, GSM1: <- +CPMS: "SM",2,40,"SM",2,40,"SM",2,40 OK
2017-06-08 04:35:02,6, GSM1: Used memory is 2 of 40
2017-06-08 04:35:02,6, GSM1: Trying to get stored message 1
2017-06-08 04:35:02,7, GSM1: -> AT+CMGR=1
2017-06-08 04:35:02,7, GSM1: Command is sent, waiting for the answer
2017-06-08 04:35:02,7, GSM1: <- +CMGR: 0,,146 07911356044902000405A15955F5000871608030434423829A8C8BC17801003200300035003600380037FF0C60A86B63572875284E007F51901A767B5F55FF0C5982975E672C4EBA64CD4F5CFF0C8BF780547CFB0039003500350035003530028BF752FF57284EFB4F5577ED4FE1621690AE4EF694FE63A57684987597624E2D8F9351659A8C8BC17801FF010020005B62DB554694F6884C005D OK
2017-06-08 04:35:02,5, GSM1: SMS received, From: 95555
2017-06-08 04:35:02,6, GSM1: Wrote an incoming message file: /var/spool/sms/incoming/GSM1.NHChff
2017-06-08 04:35:02,7, GSM1: Running eventhandler: /root/sms RECEIVED /var/spool/sms/incoming/GSM1.NHChff
2017-06-08 04:35:04,7, GSM1: Done: eventhandler, execution time 2 sec., status: 0 (0)
2017-06-08 04:35:04,3, GSM1: Exec: eventhandler said something:
2017-06-08 04:35:04,3, GSM1: ! HTTP/1.1 100 Continue
2017-06-08 04:35:04,3, GSM1: !
2017-06-08 04:35:04,3, GSM1: ! HTTP/1.1 200 OK
2017-06-08 04:35:04,3, GSM1: ! Server: nginx/1.10.0
2017-06-08 04:35:04,3, GSM1: ! Date: Wed, 07 Jun 2017 19:35:04 GMT
2017-06-08 04:35:04,3, GSM1: ! Content-Type: application/json
2017-06-08 04:35:04,3, GSM1: ! Content-Length: 637
2017-06-08 04:35:04,3, GSM1: ! Connection: keep-alive
2017-06-08 04:35:04,3, GSM1: ! Access-Control-Allow-Origin: *
2017-06-08 04:35:04,3, GSM1: ! Access-Control-Allow-Methods: GET, POST, OPTIONS
2017-06-08 04:35:04,3, GSM1: ! Access-Control-Expose-Headers: Content-Length,Content-Type,Date,Server,Connection
2017-06-08 04:35:04,3, GSM1: ! Strict-Transport-Security: max-age=31536000; includeSubdomains
2017-06-08 04:35:04,3, GSM1: !
2017-06-08 04:35:04,3, GSM1: ! {"ok":true,"result":{"message_id":15,"from":{"id":362363438,"first_name":"SMS Forward Bot","username":"sms_forward_bot"},"chat":{"id":70962251,"first_name":"Jesse","last_name":"Zhu","username":"ITJesse","type":"private"},"date":1496864104,"text":"From: 95555\nSent: 17-06-08 03:34:44\nReceived: 17-06-08 04:35:02\n\u9a8c\u8bc1\u7801205687\uff0c\u60a8\u6b63\u5728\u7528\u4e00\u7f51\u901a\u767b\u5f55\uff0c\u5982\u975e\u672c\u4eba\u64cd\u4f5c\uff0c\u8bf7\u8054\u7cfb95555\u3002\u8bf7\u52ff\u5728\u4efb\u4f55\u77ed\u4fe1\u6216\u90ae\u4ef6\u94fe\u63a5\u7684\u9875\u9762\u4e2d\u8f93\u5165\u9a8c\u8bc1\u7801\uff01 [\u62db\u5546\u94f6\u884c]"}}
2017-06-08 04:35:04,3, GSM1: Exec: eventhandler encountered errors:
2017-06-08 04:35:04,3, GSM1: !   % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
2017-06-08 04:35:04,3, GSM1: !                                  Dload  Upload   Total   Spent    Left  Speed
100  1111  100   637  100   474    337    251  0:00:01  0:00:01 --:--:--   366
2017-06-08 04:35:04,6, GSM1: Deleting message 1
2017-06-08 04:35:05,7, GSM1: -> AT+CMGD=1
2017-06-08 04:35:05,7, GSM1: Command is sent, waiting for the answer
2017-06-08 04:35:05,7, GSM1: <- OK

并且 Telegram 收到推送

Telegram 收到推送

结语

最后用 1200 日元解决了这个世纪难题,不用背两手机在包里,直接插路由器上也不用单独供电。
虽然还能实现用 bot 发送短信,但是没有这个需求就不继续做了。
然后立马登陆网银还了信用卡 :)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,923评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,154评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,775评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,960评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,976评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,972评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,893评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,709评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,159评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,400评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,552评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,265评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,876评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,528评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,701评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,552评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,451评论 2 352

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,649评论 18 139
  • 前言 互联网安全公司 Imperva Incapsula 公布的《2016年机器流量报告》(Bot Traffic...
    UCloud云计算阅读 2,143评论 0 2
  • 爱上了用下半身思考,我早已忘了喜欢是什么赶脚。
    每天都很信阅读 187评论 0 0
  • header布局 RelativeLayout里面嵌套一个LinearLayout。同时给LinearLayout...
    白帽子耗子阅读 263评论 0 0
  • 关于机票 每年出去旅行,最不喜欢的环节就是买国际机票。首先在没定好旅行时间的时候就不能买;在没计划好行程也不能买...
    含月6666阅读 512评论 0 1