LINUX.ORG.RU

Отправка Email из Java окружения в Qt

 , , , ,


0

1

Как выяснилось в этой теме:

Отправка Email из Android в Qt

для отправки Email в Android необходимо делать Java-метод, который и будет отправлять email. И этот Java-метод надо дергать из C++ окружения.

Начал я его делать (за основу можно взять пример взаимодействия Java<->C++ товарища EXL https://github.com/EXLMOTODEV/QmlDestroyTest).

В файле JniEventActivity.java добавил вот такой метод sendMail(), (Вариант 1):

public class JniEventActivity extends org.qtproject.qt5.android.bindings.QtActivity {

...

    public static void sendMail(String to, String subj, String text) {
        Log.w(TAG, "Java msg: Send mail. To:"+to+" Subj:"+subj+" Text:"+text);

        final Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND);

        emailIntent.setType("plain/text");

        // Кому
        emailIntent.putExtra(android.content.Intent.EXTRA_EMAIL,
            new String[] { to }); // Возможна отправка несколькми адресатам?

        // Тема
        emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, subj);

        // Текст
        emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, text);
        
        startActivity(Intent.createChooser(emailIntent, "Отправка письма..."));
    }

Однако этот код не компилируется и выдается ошибка:
JniEventActivity.java:113: error: non-static method startActivity(Intent) cannot be referenced from a static context
        startActivity(Intent.createChooser(emailIntent, "Отправка письма..."));
        ^
:compileDebugJavaWithJavac FAILED

То есть метод startActivity() для текущей активности не может вызваться из статического метода, потому что startActivity() нестатический.

Тогда я попробовал сделать так (Вариант 2):
        Activity activity;
        activity.startActivity(Intent.createChooser(emailIntent, "Отправка письма..."));

Но так тоже не компилируется, ошибка:
JniEventActivity.java:118: error: variable activity might not have been initialized
        activity.startActivity(Intent.createChooser(emailIntent, "Отправка письма..."));
        ^
Note: Some input files use or override a deprecated API.

Моих знаний Java в Android не хватает на то чтоб понять как правильно инициализировать Activity. Поэтому, потыкавшись, решил попробовать третий вариант.

В прототипе метода sendMail() я убрал static, вернул строку вызова отправки Email в состояние по Варианту 1, и компиляция заработала. Но при попытке отправить email происходит сегфолт вот с такими ошибками:
F art     : art/runtime/java_vm_ext.cc:410] JNI DETECTED ERROR IN APPLICATION: GetMethodID received NULL jclass
F art     : art/runtime/java_vm_ext.cc:410]     in call to GetMethodID
F art     : art/runtime/java_vm_ext.cc:410]     from void org.qtproject.qt5.android.QtNative.startQtApplication()
F art     : art/runtime/java_vm_ext.cc:410] "qtMainLoopThread" prio=5 tid=11 Runnable
F art     : art/runtime/java_vm_ext.cc:410]   | group="main" sCount=0 dsCount=0 obj=0x134499a0 self=0xb7fcb090
F art     : art/runtime/java_vm_ext.cc:410]   | sysTid=20465 nice=0 cgrp=top_visible sched=0/0 handle=0xb2d71930
F art     : art/runtime/java_vm_ext.cc:410]   | state=R schedstat=( 1185709460 105310192 298 ) utm=94 stm=24 core=1 HZ=100
F art     : art/runtime/java_vm_ext.cc:410]   | stack=0xb2c6f000-0xb2c71000 stackSize=1038KB
F art     : art/runtime/java_vm_ext.cc:410]   | held mutexes= "mutator lock"(shared held)
F art     : art/runtime/java_vm_ext.cc:410]   native: #00 pc 00371069  /system/lib/libart.so (_ZN3art15DumpNativeStackERNSt3__113basic_ostreamIcNS0_11char_traitsIcEEEEiPKcPNS_9ArtMethodEPv+160)
F art     : art/runtime/java_vm_ext.cc:410]   native: #01 pc 003508c3  /system/lib/libart.so (_ZNK3art6Thread4DumpERNSt3__113basic_ostreamIcNS1_11char_traitsIcEEEE+150)
F art     : art/runtime/java_vm_ext.cc:410]   native: #02 pc 0025a8ed  /system/lib/libart.so (_ZN3art9JavaVMExt8JniAbortEPKcS2_+740)
F art     : art/runtime/java_vm_ext.cc:410]   native: #03 pc 0025afc5  /system/lib/libart.so (_ZN3art9JavaVMExt9JniAbortVEPKcS2_St9__va_list+64)
F art     : art/runtime/java_vm_ext.cc:410]   native: #04 pc 000fda29  /system/lib/libart.so (_ZN3art11ScopedCheck6AbortFEPKcz+32)
F art     : art/runtime/java_vm_ext.cc:410]   native: #05 pc 001021ef  /system/lib/libart.so (_ZN3art11ScopedCheck5CheckERNS_18ScopedObjectAccessEbPKcPNS_12JniValueTypeE.constprop.95+2690)
F art     : art/runtime/java_vm_ext.cc:410]   native: #06 pc 00113785  /system/lib/libart.so (_ZN3art8CheckJNI11GetMethodIDEP7_JNIEnvP7_jclassPKcS6_+396)
F art     : art/runtime/java_vm_ext.cc:410]   native: #07 pc 0014e6d9  /data/app/ru.farwater.gnss.farwaterma-2/lib/arm/libQt5Core.so (???)
F art     : art/runtime/java_vm_ext.cc:410]   native: #08 pc 00150401  /data/app/ru.farwater.gnss.farwaterma-2/lib/arm/libQt5Core.so (???)
F art     : art/runtime/java_vm_ext.cc:410]   native: #09 pc 001505a7  /data/app/ru.farwater.gnss.farwaterma-2/lib/arm/libQt5Core.so (_ZNK17QJNIObjectPrivate11callMethodVIvEET_PKcS3_St9__va_list+54)
F art     : art/runtime/java_vm_ext.cc:410]   native: #10 pc 0000b6e1  /data/app/ru.farwater.gnss.farwaterma-2/lib/arm/libQt5AndroidExtras.so (_ZNK17QAndroidJniObject10callMethodIvEET_PKcS3_z+24)
F art     : art/runtime/java_vm_ext.cc:410]   at org.qtproject.qt5.android.QtNative.startQtApplication(Native method)
F art     : art/runtime/java_vm_ext.cc:410]   at org.qtproject.qt5.android.QtNative$6.run(QtNative.java:359)
F art     : art/runtime/java_vm_ext.cc:410]   at org.qtproject.qt5.android.QtThread$1.run(QtThread.java:61)
F art     : art/runtime/java_vm_ext.cc:410]   at java.lang.Thread.run(Thread.java:833)
F art     : art/runtime/java_vm_ext.cc:410]


Вот, дальше уже не знаю что делать. Вопрос: как исправить код, чтоб отправка email заработала?

Дополнительно:

В C++ коде вызов данного метода в статическом исполнении происходит так:
QAndroidJniObject::callStaticMethod<void>("ru/farwater/gnss/farwaterma/JniEventActivity",
                                "sendMail",
                                "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",
                                javaTo.object<jstring>(),
                                javaSubj.object<jstring>(),
                                javaText.object<jstring>());

А нестатический вариант вызывается так:
    QAndroidJniObject androidObj;
    androidObj.callMethod<void>("ru/farwater/gnss/farwaterma/JniEventActivity",
                                "sendMail",
                                "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",
                                javaTo.object<jstring>(),
                                javaSubj.object<jstring>(),
                                javaText.object<jstring>());

★★★★★
Ответ на: комментарий от EXL

В общем, в твоем начальном примере в классе JniEventActivity было такое свойство:

public static JniEventActivity m_instance;

Я им и воспользовался:
public static void sendMail(String to, String subj, String text) {
 ...
 m_instance.startActivity(Intent.createChooser(emailIntent, "Отправка письма..."));
}

То есть, метод должен быть статическим, отправка идет через активность m_instance, и это свойство статическое.

Я пробовал писать static Activity activity; в коде метода, но похоже что в Java нет возможности создавать статические переменные внутри метода, во всяком случае с таким кодом была ошибка.

В любом случае, благодарю.

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от Xintrea

В общем, в твоем начальном примере в классе JniEventActivity было такое свойство:

Не понял, о каком начальном примере ты говоришь. Я кинул линк на другой проект.

То есть, метод должен быть статическим, отправка идет через активность m_instance, и это свойство статическое.

Там оно ещё должно быть инициализировано как this в методе onCreate() или ещё где-либо, вне статических методов.

Я пробовал писать static Activity activity; в коде метода, но похоже что в Java нет возможности создавать статические переменные внутри метода, во всяком случае с таким кодом была ошибка.

Возможность есть. Просто Activity должен быть инициализирован.

Вообще беготня с этими static'ами это вроде Bad Practice в Java, но х. з. как там сделать более красиво.

EXL ★★★★★
()
Последнее исправление: EXL (всего исправлений: 4)
Ответ на: комментарий от EXL

Твой пример, который в стартовой мессаге упоминается.

На будущее оставлю здесь полный код Java, который вызывается из плюсов и отправляет почту:

// JniEventActivity.java
//
// For this java-class do not generate C++ header file

package ru.farwater.gnss.farwaterma;

import android.util.Log;
import android.os.Bundle;
import android.os.Vibrator;
import android.content.Context;
import android.media.AudioManager;
import android.widget.Toast;

import android.content.Intent;
import android.app.Activity;


public class JniEventActivity extends org.qtproject.qt5.android.bindings.QtActivity {
    public static Vibrator m_vibrator;
    public static JniEventActivity m_instance;

    static String TAG = "JniEventActivity";


    public JniEventActivity() {
        m_instance = this;
    }


    @Override
    public void onCreate(Bundle savedInstanceState) {
        this.setVolumeControlStream(AudioManager.STREAM_MUSIC);
        super.onCreate(savedInstanceState);
    }


    @Override
    public void onStart() {
        Log.w(TAG, "Java msg: onStart() called!");
        // NativeHelper.invokeVoidMethod(100); // Не работает на Qt 5.11.2, баг https://bugreports.qt.io/browse/QTBUG-68813
        super.onStart();
    }


    @Override
    public void onStop() {
        Log.w(TAG, "Java msg: onStop() called!");
        // NativeHelper.invokeVoidMethod(101); // Отключено, вместо этого вызова сделан вызов по applicationStateChanged
        super.onStop();
    }


    @Override
    public void onDestroy() {
        Log.w(TAG, "Java msg: onDestroy() called!");
        super.onDestroy();
    }


    public static void invoke(int x) {
        final int z = x;
        m_instance.runOnUiThread(new Runnable() {
            public void run() {
                Toast.makeText(m_instance, "Java msg: Invoke from C++ => Java: " + String.valueOf(z) + " (Button)",
                                           Toast.LENGTH_SHORT).show();
            }
        });

        NativeHelper.invokeVoidMethod(x);
    }


    public static void vibrate(int x) {
        if (m_vibrator == null) {
            if (m_instance != null) {
              m_vibrator = (Vibrator) m_instance.getSystemService(Context.VIBRATOR_SERVICE);
              m_vibrator.vibrate(x);
            }
        } else {
            m_vibrator.vibrate(x);
        }
        Log.w(TAG, "Java msg: Vibro");
    }


    public static void sendMail(String to, String subj, String text) {
        Log.w(TAG, "Java msg: Send mail. To:"+to+" Subj:"+subj+" Text:"+text);

        final Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND);

        emailIntent.setType("plain/text");

        // Кому
        emailIntent.putExtra(android.content.Intent.EXTRA_EMAIL,
            new String[] { to }); // Возможна отправка несколькми адресатам?

        // Тема
        emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, subj);

        // Текст
        emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, text);

        // Аттачи
        // emailIntent.putExtra(android.content.Intent.EXTRA_STREAM,
        //                      Uri.parse("file://"
        //                      + Environment.getExternalStorageDirectory()
        //                      + "/Клипы/SOTY_ATHD.mp4"));
        // emailIntent.setType("text/video");

        // Отправка
        m_instance.startActivity(Intent.createChooser(emailIntent, "Отправка письма..."));
    }
}

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от Xintrea

Твой пример, который в стартовой мессаге упоминается.

А, ок. Там просто для создания Toast'а в GUI-потоке оно используется.

Я просто вспомнил кинул линк в первом сообщения на другой и реальный проект https://github.com/EXL/Gish, где как раз используется старт Activity Web-браузера из нативной либы через JNI. Там кстати Qt не используется, но используется SDL2. Но сама суть не меняется. Всё так же надо лазить то внутрь C-кода, то внутрь Java-кода и делать такие вот обёртки.

EXL ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.