2020-06-25

AppleScript 实现短信自动转发

背景:这段时间某位同事需要频繁登录我的账号,并且要验证手机验证码,每次都需要我手动将验证码转发给他,觉得非常的麻烦,便想看一下有没有什么能够解放双手的办法,然后发现了AppleScript这么一个非常好用的东西 :)

所需配置

  • Mac 电脑:既然是使用AppleScript,那么一台MAC电脑自然是不可少的(macOS Catalina 10.15.5)
  • iPhone:如果消息类型是iMessage的话,则只需要MAC上登录苹果账号就可以,如果消息类型是SMS的,则需要利用苹果的生态,iphone 上的消息能够自动转发到MAC上(IOS 8 以后支持)。

AppleScript

什么是AppleScript?

AppleScript是用来编写运行于mac的脚本的,并且能够操作应用程序。苹果官方也要求开发mac上的软件需要留出能够共AppleScript能够操作的方法。利用AppleScript我们能非常方便实现一些平常工作中重复工作的脚本化,提升工作效率,避免重复劳动。

基础语法

AppleScript 的语法非常接近自然语言,几乎没有标点符号,语法不像其他语言那样严格

变量定义

-- 将百度网址赋值给变量url_strset url_str to "https://www.baidu.com"

通知

-- 将百度网址赋值给变量url_strset url_str to "https://www.baidu.com"-- 通知display notification "url set success"

操作应用

-- 将百度网址赋值给变量url_strset url_str to "https://www.baidu.com"-- 将bing网址赋值给变量url_str2set url_str2 to "https://www.bing.com"-- 通知display notification "url set success"-- 操作应用tell application "Google Chrome"	-- 创建新窗口	set newWin to make new window	-- 获取新窗口tab	set theTab to get active tab of newWin	-- 操作tab	tell theTab		-- 设置tabURL		set URL of theTab to url_str		-- 访问		go forward		-- 延迟3秒		delay 3		--重新设置tabURL		set URL of theTab to url_str2		go forward	end tellend tell

字典

苹果官方会要求mac软件的开发提供能够操作应用软件的方法,可以通过字典查询能否由AppleScript操控软件

字典打开方式

Script Editer -> 打开词典 -> 选择想要操作的软件

"open_dict.png"

chrome dictionary.
"chrome_dict"

AppleScript Language Guide

了解 AppleScript 的基础语法是掌握 AppleScript 自动化的第一步,在对 AppleScript 有了一定的了解后,在日后发现自己有重复操作时,就可以先想想可以如何通过 AppleScript 解决它

问题解决

回到正题,因为对AppleScript 有过一定了解,并且也做过简单的测试,所以第一时间想到的就是能不能用自动话脚本来处理重复的短信转发工作(在这之前还从没用AppleScript解决过现实问题)

发送短信

首先需要的就是打开字典,因为Message本身就是苹果开发的,所以肯定会有丰富的API供我们使用的

"message_dict_send.png"

通过翻找,我们能够基本定位我们发送短信需要用到的send方法,send方法中还需要我们明确一个buddy,继续查看buddy

"message_dict_buddy.png"

查看我们的buddy,他是包含在一个service里面的,继续service ...

"message_dict_service.png"

service 上层为application包含,因此我们可以书写我们的脚本了

tell application "Messages"	send "test" to buddy "+86199xxxx" of service "SMS"end tell

非常简单的一段代码,可以测试发送了。在测试的过程中发现需要有和该号码发过消息的记录(即需要打开有一个窗口)

"message_send_test.png"

事件监听

在能够成功发送短信后,我们距离解放双手已经很近了,接下来我们只需要在接收到验证码信息的时候,调用我们的发送脚本将我们收到的消息转发出去就大功告成了:)

继续查看我们的字典,有一个message received 事件,看字面上的意思就能满足我们的需要,就是他了

"message_dict_message_received.png"

很简单,我们只需要获取到我们需要的消息,以及发送给我们的人用来判断(毕竟不能把所有的消息都转发出去)

using terms from application "Messages"	on message received theMessage from theBuddy		-- 通知接收到消息		display notification "message"		-- 将Message App可见		set visible of window "Messages" to true		-- 将Message App置顶		set frontmost of window "Message" to true	end message receivedend using terms from

事情到这里就结束了嘛?哪有那么简单,正所谓"天之道,没那么容易让你成功~"

经过不断的测试,发现这个脚本根本就没达到我的预期,没有通知也没有置顶,是我哪里写的有问题嘛?好嘛,知错要改,要虚心学习。百度~,嗯,查不到,害,谷歌~(个人习惯,先百度,当发现查不到想要的信息或者百度上全是同一篇文章抄来抄去的时候才谷歌,毕竟谷歌是不被允许,我可是乖孩子)

不断的变换关键词及描述,用我的散装英语终于找到了一些解决办法
发现我的脚本写的是没有问题的,只是还少一些操作步骤。例如

copy the script into a new AppleScript Editor document and save it in ~/Library/Application Scripts/com.apple.iChat/Then activate it by selecting it in Messages -> Preferences -> General -> AppleScript Handler:

以及

AppleScript file copied to ~/Library/Scripts/Messages by Messages, it started to work.

不同的路径,但是好像都需要拷贝,于是分别考到目录下,但是一直没有找到Message -> Preference —> General(发现我的MAC好像和广大网友不太一样啊,买到了假货了吧)总之还是不成功,继续google...

终于,原来Message.app Message Received Event HandlermacOS High Sierra 10.13.4版本被移除,并且开通了Business Chat emmmmmmm.....,害~

分析数据库

事件的方式走不通了,只能换一种方式了。还可以用什么方式呢,于是我想到了一种可能,我的这些消息,哪怕时间再久远都能查到,他是怎么存放的呢。
OK,有思路就有方向,最后不断的搜索发现是存在目录/Users/herbert/Library/Messages下 的chat.db文件中

用sqlite打开看一下

sqlite3 /Users/herbert/Library/Messages/chat.db

"message_sqlite_tables.png"

查看表结构及表内部分数据

.schema messageselect * from message order by ROWID desc limit 5;

最终根据梳理的表结构关系,及传入我需要查询的号码整理SQL

-- 查询一分钟内来自指定号码xxxxxx_number的短信SELECT text, handle_id,date,datetime(date/1000000000 + strftime('%s','2001-01-01'), 'unixepoch', 'localtime') as date_utc FROM message T1 INNER JOIN chat_message_join T2 ON T1.ROWID=T2.message_id INNER JOIN chat T3 ON T2.chat_id=T3.ROWID AND T3.chat_identifier = 'xxxxxx_number' where datetime(date/1000000000 + strftime('%s','2001-01-01'), 'unixepoch', 'localtime') > datetime('now','localtime','-1 minute') ORDER BY T1.date;

在查询数据的时候还发现了一个不常见的日期存储(我之前没有见过)一个18位的时间数字
"message_sqlite_date.png"
处理方式:
datetime(date/1000000000 + 978307200,'unixepoch','localtime').
datetime(date/1000000000+ strftime('%s','2001-01-01'),'unixepoch','localtime')

编写脚本

我们已经拿到我们需要的数据了,接下来就只需要每个一分钟取一次数据,如果能够去到数据,那么调用我们发送短信的脚本就OK了

编写脚本auto_forward.sh

 #/bin/shphone="+86xxxx"call_apple(){ 	while read line	do		osascript /Users/herbert/Documents/AppleScript/ForwardMessage/SendMessage.scpt $line $phone	done}export -f call_applesqlite3 /Users/herbert/Library/Messages/chat.db '.read /Users/herbert/Documents/AppleScript/ForwardMessage/select.txt' | call_apple

将我们的sql存在单独的文件里,方便修改select.txt

SELECT text FROM message T1 INNER JOIN chat_message_join T2 ON T1.ROWID=T2.message_id INNER JOIN chat T3 ON T2.chat_id=T3.ROWID AND T3.chat_identifier = 'from_number' where datetime(date/1000000000 + strftime('%s','2001-01-01'), 'unixepoch', 'localtime') > datetime('now','localtime','-1 minute') ORDER BY T1.date;

SendMessage.scpt

on run argv	set msgContent to item 1 of argv	set phone to item 2 of argv	sendMsg(msgContent, phone)end runon sendMsg(msgContent, phone)	tell application "Messages"		send msgContent to buddy phone of service "SMS"	end tellend sendMsg

万事具备,只需要加入crontab中就行了

crontab -e*/1 * * * * sh /Users/herbert/Documents/AppleScript/ForwardMessage/auto_forward.sh

此处在测试的时候还是没有达到预期,但是单独执行脚本的时候能够成功,推测是cron的问题,于是查看日志
vim /var/mail/herbert
果然发现问题
sh: /Users/herbert/Documents/test/demo.sh: Operation not permitted

此问题会在Mojave 10.14, Catalina 10.15 以及后续版本出现
解决方法:系统偏好设置 -> 安全性与隐私 -> 隐私 -> 完全磁盘访问权限 -> 添加cron

AppleScript 实现短信自动转发

No comments:

Post a Comment