iTunes音乐搜索
先了解你将做出什么
应用介绍
前面的教程里,App 用的数据都是我们自己写死在代码块里的。可真正好玩的 App, 数据都来自网络——天气、歌单、地图、快递,全都是先向服务器要一份数据,再显示出来。
这一篇就做一个能联网的 App:输入歌手的名字,它去 iTunes 的公开接口搜一首歌, 把专辑封面显示出来,还能直接点开试听。

学完你会用到两样东西,它们在很多联网 App 里都是同一套路:
- Web客户端组件——向网址发一个请求,等服务器把数据送回来。
- 字典——网络返回的数据是一大坨 JSON 文本,用字典能按名字把想要的值取出来。
iTunes音乐搜索教程(难度系数:★★)
找素材并上传
这一篇不用上传任何素材,专辑封面是从网上取回来的。
注意:iTunes 的接口在国内访问速度不稳定,测试时如果转很久没反应,多半是网络问题, 换个时间或者换个网络再试。
App基本逻辑设计
- 在输入框里打上歌手的名字,点“搜索”按钮。
- App 把名字拼进一个网址,向 iTunes 发出请求,然后等。
- 服务器把结果送回来,App 从里面取出歌名、歌手、封面图和试听地址,显示出来并开始播放。
整个过程的关键是第 2 步和第 3 步是分开的:请求发出去之后 App 不会原地等着, 而是先去干别的;等数据回来了,再由一个专门的事件来处理。这一点后面会细讲。
搭建界面
拖入这些组件,改成下面的名字:
| 组件(在哪个分类下) | 改名为 | 要改的属性 |
|---|---|---|
| 图像(用户界面) | 图像_封面 |
宽度、高度都设 200 像素 |
| 文本输入框(用户界面) | 文本输入框_歌手 |
宽度设“充满”,提示填“输入歌手名,比如 周杰伦” |
| 按钮(用户界面) | 按钮_搜索 |
文本改成“搜索” |
| 水平布局(界面布局) | 水平布局_结果 |
宽度设“充满”,水平对齐设“居中:3” |
| 标签(用户界面),放进水平布局_结果 | 标签_歌手 |
文本清空 |
| 标签(用户界面),放进水平布局_结果 | 标签_歌名 |
文本清空 |
| Web客户端(数据通信) | Web客户端1 |
不用改 |
| 播放器(多媒体) | 音频播放器1 |
不用改 |
再把 Screen1 的“水平对齐”也设成“居中:3”,整个界面就居中了。
最后两个是非可视组件,拖进去以后不会出现在手机屏幕上,而是排在下方的 “非可视组件”区域里,这是正常的。
把名字拼成一个网址
iTunes 的搜索接口长这样:
https://itunes.apple.com/search?term=周杰伦&entity=song&limit=1
term= 后面跟歌手名,entity=song 表示只要歌曲,limit=1 表示只要一条结果。
你可以先把这个网址复制到浏览器里打开看看,返回的就是一大段 JSON 文本。
App 要做的就是把用户输入的名字拼到 term= 后面。我们写成一个过程,
这样以后想在别的地方也搜一次,调用一下就行:
procedure 搜索歌曲(歌手名) {
Web客户端1.Url = join("https://itunes.apple.com/search?term=",
Web客户端1.UriEncode(歌手名),
"&entity=song&limit=1")
Web客户端1.Get()
}
注意 UriEncode 这一步,别省。 网址里不能直接出现中文和空格,
周杰伦 得先转换成 %E5%91%A8%E6%9D%B0%E4%BC%A6 这样的形式才能发出去。
UriEncode 就是干这个的——少了它,搜英文歌手名(Jay Chou 中间有空格)
和搜中文歌手名都会失败。
Web客户端1.执行GET请求() 是真正把请求发出去的那一下。
点按钮发起搜索
when 按钮_搜索.Click() {
if trim(文本输入框_歌手.Text) = "" {
标签_歌名.Text = "先输入一个歌手名吧"
} else {
标签_歌名.Text = "搜索中…"
搜索歌曲(trim(文本输入框_歌手.Text))
}
}
trim 把用户不小心敲进去的前后空格去掉。空输入直接挡回去,不用白跑一趟网络。
搜索中先把标签改成“搜索中…”,是为了让用户知道 App 没死机——网络请求要花一两秒, 这一两秒里如果界面毫无反应,用户就会以为按钮坏了。这类小事最影响使用感受。
数据回来了:GotText 事件
请求发出去之后,App 不会停在那里等。等服务器把数据送回来,
Web客户端1 会触发一个叫 GotText 的事件,我们要处理的一切都在这个事件里。
它带四个参数:
| 参数 | 是什么 |
|---|---|
url |
刚才请求的那个网址 |
responseCode |
服务器的状态码,200 表示成功 |
responseType |
数据的类型 |
responseContent |
正文,我们要的东西全在这里 |
服务器送回来的 responseContent 长这样(省略了很多):
{
"resultCount": 1,
"results": [
{
"artistName": "周杰伦",
"trackName": "晴天",
"artworkUrl100": "https://.../100x100bb.jpg",
"previewUrl": "https://.../preview.m4a"
}
]
}
看懂它的结构就好办了:最外层是一个字典(用 {} 括起来,里面是「名字: 值」一对一对的),
results 这个名字对应的值是一个列表(用 [] 括起来),列表里的第 1 项又是一个字典,
歌名、歌手、封面、试听地址都在这个字典里。
从数据里把想要的取出来
Web客户端1.用字典解码JSON文本 能把上面那段文本变成 App 能操作的字典。
变成字典之后,用 dictpath(在“字典”分类里,块上写的是「获取路径对应的值」)
就能按名字一路取下去:
先声明两个全局变量存中间结果,再在事件里用:
global 搜索结果 = ""
global 试听地址 = ""
when Web客户端1.GotText(url, responseCode, responseType, responseContent) {
搜索结果 = Web客户端1.JsonTextDecodeWithDictionaries(responseContent)
试听地址 = dictpath(搜索结果, list("results", 1, "previewUrl"), "")
if 试听地址 = "" {
标签_歌手.Text = ""
标签_歌名.Text = "没搜到这个歌手,换个名字试试"
} else {
标签_歌手.Text = dictpath(搜索结果, list("results", 1, "artistName"), "")
标签_歌名.Text = dictpath(搜索结果, list("results", 1, "trackName"), "")
图像_封面.Picture = dictpath(搜索结果, list("results", 1, "artworkUrl100"), "")
音频播放器1.Source = 试听地址
音频播放器1.Start()
}
}
list("results", 1, "previewUrl") 就是一条路径,意思是:
先按名字取 results,再取它的第 1 项,再按名字取 previewUrl。
跟着数据的结构一层层走下去,写法和上面那段 JSON 长得几乎一样。
最后那个 "" 是取不到时的默认值。这一点很关键:用户随手输了个不存在的歌手,
服务器会返回一个空列表,这时候路径走不通,dictpath 就老老实实给你一个空字符串,
App 不会崩。我们正是靠试听地址是不是空的,来判断这次到底搜到没有。
开始测试
用 AI伴侣 连上手机,输入一个歌手名点搜索:
- 能看到专辑封面出来吗?
- 歌手名和歌名对得上吗?
- 有没有声音?
- 故意输入一串乱码(比如
asdfgh),是不是提示“没搜到这个歌手”,而不是闪退?
第 4 条最容易被跳过,但恰恰是它决定了 App 好不好用。
剩余工作
- 把
limit=1改成limit=10,一次搜回 10 首,用列表显示器让用户挑着听。 (路径里的1换成循环变量就行) - 加一个“停止”按钮,调用
音频播放器1.停止()。 - 搜索时把按钮设成不可用(
按钮_搜索.启用 = false),数据回来再恢复, 防止用户连点好几次。 - iTunes 返回的数据里还有专辑名(
collectionName)、时长(trackTimeMillis)、 价格(trackPrice),照着dictpath的写法都能取出来,试试看。 - 换一个接口试试——只要返回的是 JSON,这一整套做法都能照搬, 区别只在于路径里的名字不一样。
后记
为什么要用字典,而不是一层层数位置?
App Inventor 里还有一种老办法:把 JSON 解码成一串嵌套的列表,然后用「选择列表项」
一层一层往里挖,写出来是 选择列表项(选择列表项(选择列表项(数据, 2), 2), 1) 这样。
它能用,但有两个毛病:一是读不懂,光看代码块完全不知道取的是什么;
二是太脆,服务器哪天在返回的数据里多加一个字段,位置全变了,整个 App 就废了。
按名字取就没这个问题。results → 第1项 → previewUrl 这条路径,
不管服务器怎么增删别的字段,它都还在那儿。
这一篇真正学到的东西,其实不是 iTunes 怎么搜歌,而是联网 App 的通用套路: 拼网址 → 发请求 → 在 GotText 里等数据 → 按路径取值 → 显示。 天气、汇率、快递、新闻,全都是这四步,换的只是网址和路径里的名字。
加油ヾ(◍°∇°◍)ノ゙
卡在哪一步?直接查操作
不用退出当前教程。速查会在新页面打开,查完回来继续刚才的进度。