QCloudMusicApi

Qt C++版 网易云音乐 API

View the Project on GitHub s12mmm3/QCloudMusicApi

QCloudMusicApi: API 参考

QCloudMusicApi API 由以下组件组成:

NeteaseCloudMusicApi类和ApiHelper类中的所有方法均通过Q_INVOKABLE宏注册到Qt元对象系统中,支持反射调用

module.hapihelper.hapi_c.h为外部调用,其他类均为内部调用

module.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.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

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);
    }

调用方式参考跨语言调用