Qt C++版 网易云音乐 API NeteaseCloudMusicApi
QCloudMusicApi API 由以下组件组成:
module.h: 封装了NeteaseCloudMusicApi类,实现了所有的API方法apihelper.h: 封装了ApiHelper类,将所有API接口的调用都封装在了一个方法中,支持设置全局的Cookie与网络代理api_c.h: 提供C语言接口,实现对ApiHelper类的跨语言调用的支持plugins.h: Plugins插件类,供NeteaseCloudMusicApi类调用util/request.h: Request网络接口类,通过事件循环实现同步调用网络接口util/crypto.h: 通过调用openssl实现API底层的加解密功能,支持rsa、aes的加解密等util/index.h: Index类,封装了一些通用的方法util/logger.h: 管理QCloudMusicApi的日志输出NeteaseCloudMusicApi类和ApiHelper类中的所有方法均通过Q_INVOKABLE宏注册到Qt元对象系统中,支持反射调用
module.h、apihelper.h和api_c.h为外部调用,其他类均为内部调用
module.h 封装了NeteaseCloudMusicApi类,参考Node.js项目的module目录,实现了所有API方法。
继承了QObject类并声明了Q_OBJECT宏,用于实现Qt的反射调用
class QCLOUDMUSICAPI_EXPORT NeteaseCloudMusicApi : public QObject {
Q_OBJECT
public:
explicit NeteaseCloudMusicApi(QObject* parent = nullptr);
// 声明所有方法
}
类中所有方法均以Q_INVOKABLE QVariantMap 方法名(QVariantMap)的格式定义;Q_INVOKABLE用于将方法注册到Qt元对象系统中,函数的入参和返回值均为QVariantMap类型
// 歌手全部歌曲
Q_INVOKABLE QVariantMap artist_songs(QVariantMap);
调用方式:
NeteaseCloudMusicApi api;
qDebug() << api.artist_songs({
{ "id", "1408586353" },
{ "offset", 0 },
{ "limit", 100 }
});
apihelper.h 封装了ApiHelper类,通过反射机制将所有API接口的调用都封装在了一个方法中,支持设置全局的Cookie与网络代理,实现对Cookie的管理;所有方法均使用Q_INVOKABLE声明
/**
* @brief 调用API的成员函数
* @param member 成员函数名
* @param arg 调用参数
* @return QVariantMap 返回调用结果
*/
Q_INVOKABLE QVariantMap invoke(QString member, QVariantMap arg);
使用Qt的元对象系统对NeteaseCloudMusicApi类的API接口反射调用,若找不到对应的方法,则返回一个空的QVariantMap
调用invoke方法时,若参数中传有Cookie,则将其保存下来,下一次调用无需传入Cookie
当调用登录等接口返回值中有Cookie,也将其保存下来,存放于内存中
QVariantMap ret;
QMetaObject::invokeMethod(this, member.toUtf8(),
Qt::DirectConnection,
Q_RETURN_ARG(QVariantMap, ret),
Q_ARG(QVariantMap, arg));
return ret;
调用方式:
ApiHelper helper;
qDebug() << helper.invoke("artist_songs",
{
{ "id", "1408586353" },
{ "offset", 0 },
{ "limit", 100 }
});
api_c.h 提供C语言接口,实现对ApiHelper类跨语言调用的支持,所有方法用extern "C"包裹,声明为C语言函数,传入参数均为C语言类型
/**
* @brief 通过反射调用API的成员函数
* @param memberName 调用的函数的名称
* @param value 函数参数的JSON格式字符
* @return 调用结果的JSON格式字符串
*/
QCLOUDMUSICAPI_EXPORT const char* invoke(char* memberName, char* value);
调用前创建一个QCoreApplication单例,提供事件循环支持,否则无法同步接收网络请求
auto currentPath = QDir::currentPath().toStdString();
// 创建一个QCoreApplication单例,用于支持事件循环QEventLoop
if (!QCoreApplication::instance()) {
int argc = 1;
char* argv[1]{ (char*)currentPath.c_str() };
app = new QCoreApplication(argc, argv);
}
调用方式参考跨语言调用