Получение IMEI Android-устройства средствами Qt

В свете выхода релиза Qt 5.2.0 с заявленной поддержкой андроида, готовой к продакшену, решил наконец-то попробовать, что же оно из себя представляет — разработка под андроид средствами Qt. И сразу же у меня возник вопрос получения IMEI устройства (необходимо для разрабатываемого приложения). Сходу сделать не получилось, пришлось потратить некоторое время (основная проблема в отсутствии знаний jni). Кому интересно — просим под кат.

Реализация поставленной задачи средствами Java достаточно тривиальна, и найти решение в интернете не представляет проблем. Таким образом, задача сводилась к реализации этого кода средствами Qt.

Qt 5.2 включает в себя классы для доступа к нативным функциям андроида. Это QAndroidJniEnvironment и QAndroidJniObject. Для их использования в .pro файле необходимо добавить

QT += androidextras


Сразу приведу весь метод получения IMEI, а потом вкратце опишу особенности.

#include <QString>
#include <QAndroidJniEnvironment>
#include <QandroidJniObject>


QString getDeviceImei()
{
        QAndroidJniEnvironment env;
        
        jclass contextClass = env->FindClass("android/content/Context");
        jfieldID fieldId = env->GetStaticFieldID(contextClass, "TELEPHONY_SERVICE", "Ljava/lang/String;");
        jstring telephonyManagerType = (jstring) env->GetStaticObjectField(contextClass, fieldId);

        jclass telephonyManagerClass = env->FindClass("android/telephony/TelephonyManager");
        jmethodID methodId = env->GetMethodID(contextClass, "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;");

       QAndroidJniObject qtActivityObj = QAndroidJniObject::callStaticObjectMethod("org/qtproject/qt5/android/QtNative",  "activity", "()Landroid/app/Activity;");
        jobject telephonyManager = env->CallObjectMethod(qtActivityObj.object<jobject>(), methodId, telephonyManagerType);

        methodId = env->GetMethodID(telephonyManagerClass, "getDeviceId", "()Ljava/lang/String;");
        jstring jstr = (jstring) env->CallObjectMethod(telephonyManager, methodId);

        jsize len = env->GetStringUTFLength(jstr);
        char* buf_devid = new char[32];
        env->GetStringUTFRegion(jstr, 0, len, buf_devid);
        QString imei(buf_devid);
        delete buf_devid;
        return imei;
}

В самом начале объявляем переменную env, которая обеспечит нам доступ к функциям jni.
Далее находим класс контекста, id его статического поля TELEPHONY_SERVICE и, собственно, само значение этого поля.
Тут нужно уточнить, что результатом вызова всех методов jni является тип jobject, поэтому используем приведение к типу jstring. Далее находим класс TelephonyManager, и id метода getSystemService класса контекста.

Следующим шагом (решение которого лично у меня заняло больше всего времени) является получение объекта activity. Как видно, это достаточно тривиально, если знаешь как, простите за каламбур.
После мы получаем объект telephonyManager, находим id его метода getDeviceId. Вызываем этот метод и получаем строку imei (не забываем снова приведение типов).
Дальше преобразовываем jstring к типу Qstring.

В принципе, ничего сложного во всём этом нет, но возможно, эта информация будет кому-то полезна и позволит сэкономить немного времени.
Tags:
qt, android, jni

You can't comment this post because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author's username will be hidden by an alias.