如何使使用Qt打电话直接从应用程序? [英] How to make a call with Qt directly from the application?

查看:279
本文介绍了如何使使用Qt打电话直接从应用程序?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我要实现我的应用程序的Dialer-功能。其实,它的工作要做,但它的作品,我不想要的方式。当按钮为pressed,原生拨号器打开并等待pressing按钮。是否有可能直接调用没有双pressing? 这是我的code

 按钮{
        ID:callButton
        anchors.centerIn:父母
        文本:拨打电话
        onClicked:Qt.openUrlExternally('电话:77051085322)
    }
 

解决方案

而在iOS的通话可以发出直接,同样不适用于Android系统。为了克服你可以定义一个C ++类包装负责处理呼叫,这取决于当前操作系统上的问题。这个类的一个实例被注册为上下文属性并直接在QML使用。

在类中,你可以利用Android的原生API,它提供了通过意图操作自动拨号功能 ACTION_CALL (但请记住,有在使用它某些限制)。通常,在Android中你写的:

 意图callIntent =新callIntent(Intent.ACTION_CALL);
callIntent.setPackage(com.android.phone); //力原生拨号器(安卓小于5)
callIntent.setPackage(com.android.server.telecom); //力原生拨号器(Android的> = 5)
callIntent.setData(Uri.parse(电话:+号));
callIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(callIntent);
 

通过设定包我们可以迫使本地拨号器的使用情况。如果没有它,用户就可以迅速拨号器(例如:Skype,Viber的,等等)中进行选择的显然,如果其他已安装的设备上的。棒棒糖和previous释放,使得有必要检查SDK在运行时设置的正确的一个之间的系统拨号器包改变。


要++,你需要的Qt Android的额外调用这些API用C尤其 QAndroidJniObject 而且在自定义Android清单的相关权限。只需添加到您的的.pro 文件:

  Android版本:QT + = androidextras只包含(#include)在Android的构建
 

和下面的一行到你的清单:

 <使用-权限的Andr​​oid:名称=android.permission.CALL_PHONE/>
 

如果你没有定义一个定制清单再补充。由于Qt Creator的3.3只是去项目>构建与GT;构建Android APK>创建模板生成自定义的清单。


我们班的标题如下所示 - 构造函数/析构丢失:

  #ifndef的WRAPPER_H
#定义WRAPPER_H
#包括< QObject的>
#包括<的QString>
#包括< QDebug>
#如果定义(Q_OS_IOS)
#包括< QUrl>
#包括< QDesktopServices>
#elif指令定义(Q_OS_ANDROID)
#包括< QtAndroid>
#包括< QAndroidJniObject>
#ENDIF

#包括< QDesktopServices>
#包括< QUrl>

类包装:公众的QObject
{
    Q_OBJECT
上市:
    Q_INVOKABLE无效directCall(即QString号);
};

#ENDIF // WRAPPER_H
 

相应的源文件,如下所示 - 再构造函数/析构丢失:

 的#includewrapper.h

无效包装:: directCall(QString的数量)
{
#如果定义(Q_OS_IOS)
    QDesktopServices ::的OpenURL(QUrl(QString的(电话://%1).arg(编号)));
#elif指令定义(Q_OS_ANDROID)
    //获得了Qt的android活动
    QAndroidJniObject活动= QAndroidJniObject :: callStaticObjectMethod(组织/ qtproject / QT5 /安卓/ QtNative,活动,()Landroid / APP /活动;);
    //
    如果(activity.isValid()){
    //真正的Java code和C ++ code
    //意图callIntent =新callIntent(Intent.ACTION_CALL);
    QAndroidJniObject callConstant = QAndroidJniObject :: getStaticObjectField<的jstring>(机器人/内容/意图,ACTION_CALL);
    QAndroidJniObject callIntent(机器人/内容/意图,(Ljava /朗/字符串;)V,callConstant.object());
    // callIntent.setPackage(com.android.phone); (小于=4.4瓦特)intent.setPackage(com.android.server.telecom); (大于= 5)
    QAndroidJniObject包;
    如果(QtAndroid :: androidSdkVersion()> = 21)
        包= QAndroidJniObject :: fromString(com.android.server.telecom);
    其他
        包= QAndroidJniObject :: fromString(com.android.phone);
    callIntent.callObjectMethod(setPackage,(Ljava /朗/字符串;)Landroid /内容/意图;,package.object<的jstring>());
    // callIntent.setData(Uri.parse(电话:+号));
    QAndroidJniObject jNumber = QAndroidJniObject :: fromString(QString的(电话:%1)。ARG(数));
    QAndroidJniObject URI = QAndroidJniObject::callStaticObjectMethod("android/net/Uri","parse","(Ljava/lang/String;)Landroid/net/Uri;", jNumber.object());
    callIntent.callObjectMethod(使用setData,(Landroid / NET /乌里;)Landroid /内容/意图;,uri.object< jobject>());
    // callIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    jint标志= QAndroidJniObject :: getStaticField< jint>(机器人/内容/意图,FLAG_ACTIVITY_NEW_TASK);
    callIntent.callObjectMethod(setFlags,(我)Landroid /内容/意图;,标志);
    // startActivity(callIntent);
    activity.callMethod&其中;空隙>(startActivity,(Landroid /内容/意图;)VcallIntent.object&其中; jobject>());
}
    其他
        qDebug()&其中;&其中; 蹊跷的Qt的活动......;
#其他
    qDebug()&其中;&其中; 这里什么也不做......;
#ENDIF
}
 

由于在一开始讨论的,您可以包括这个类作为一个上下文属性的一个实例。该为此目的如下所示:

 的#include<的QApplication>
#包括< QQmlContext>
#包括< QQmlApplicationEngine>
#包括wrapper.h

INT主(INT ARGC,字符* argv的[])
{
    QApplication的应用程序(ARGC,ARGV);

    QQmlApplicationEngine发动机;
    包装器JW;
    engine.rootContext() - > setContextProperty(来电,和放大器; JW);
    engine.load(QUrl(QStringLiteral(QRC:/main.qml)));

    返回app.exec();
}
 

最后,在QML可以简单的写:

 按钮{
    ID:callButton
    anchors.centerIn:父母
    文本:拨打电话
    onClicked:caller.directCall(+ 0123456789)
}
 

在code可以很容易地扩展,以支持也WinPhone,同时保持相同的QML接口。最后,有条件的夹杂物的使用保证了code编译正确,即使使用的套件飞改变。

最后一点,我想补充一点,谷歌播放政策不严格的苹果App Store的政策。因此,一个应用程序拒绝因 ACTION_CALL 的使用是不太可能发生。

I want to implement a dialer-feature in my app. Actually, it's done, but it works the way I don't want to. When button is pressed, native dialer opens and waiting for pressing a button. Is it possible to call directly without double pressing? Here's my code:

Button {
        id: callButton
        anchors.centerIn: parent
        text: 'Make a call'
        onClicked: Qt.openUrlExternally('tel:+77051085322')
    }

解决方案

Whereas in iOS the call can be issued directly, the same does not apply to Android. To overcome the problem you can define a C++ class Wrapper which handles the call, depending on the current OS. An instance of this class is registered as a context property and directly used in QML.

Inside the class you can exploit Android native APIs which provide the automatic dialing feature via the Intent action ACTION_CALL (but remember that there are some restrictions in using it). Typically in Android you write:

Intent callIntent = new callIntent(Intent.ACTION_CALL);
callIntent.setPackage("com.android.phone");          // force native dialer  (Android < 5)
callIntent.setPackage("com.android.server.telecom"); // force native dialer  (Android >= 5)
callIntent.setData(Uri.parse("tel:" + number));
callIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(callIntent);

By setting the package we can force the usage of the native dialer. Without it the user would be prompt to choose among available dialers (i.e. Skype, Viber, etc...) clearly if other are installed on that device. The system dialer package changed between Lollipop and the previous releases so that it is necessary to check the SDK at runtime to set the correct one.


To call these APIs in C++ you need the Qt Android Extras and in particular QAndroidJniObject but also the related permissions in your custom Android manifest. Just add to your .pro file:

android: QT += androidextras  #included only in Android builds

and the following row to your manifest:

<uses-permission android:name="android.permission.CALL_PHONE"/>

If you did not define a custom manifest just add one. As of Qt Creator 3.3 just go to Projects > Build > Build Android APK > Create Templates to generate the custom manifest.


The header of our class looks like the following - constructor/deconstructor missing:

#ifndef WRAPPER_H
#define WRAPPER_H
#include <QObject>
#include <QString>
#include <QDebug>
#if defined(Q_OS_IOS)
#include <QUrl>
#include <QDesktopServices>
#elif defined(Q_OS_ANDROID)
#include <QtAndroid>
#include <QAndroidJniObject>
#endif

#include <QDesktopServices>
#include <QUrl>

class Wrapper: public QObject
{
    Q_OBJECT
public:
    Q_INVOKABLE void directCall(QString number);
};

#endif // WRAPPER_H

The corresponding source file looks like the following - again constructor/deconstructor missing:

#include "wrapper.h"

void Wrapper::directCall(QString number)
{
#if defined(Q_OS_IOS)
    QDesktopServices::openUrl(QUrl(QString("tel://%1").arg(number)));
#elif defined(Q_OS_ANDROID)
    // get the Qt android activity
    QAndroidJniObject activity =  QAndroidJniObject::callStaticObjectMethod("org/qtproject/qt5/android/QtNative", "activity", "()Landroid/app/Activity;");
    //
    if (activity.isValid()){
    // real Java code to C++ code
    // Intent callIntent = new callIntent(Intent.ACTION_CALL);
    QAndroidJniObject callConstant = QAndroidJniObject::getStaticObjectField<jstring>("android/content/Intent", "ACTION_CALL");
    QAndroidJniObject callIntent("android/content/Intent",  "(Ljava/lang/String;)V", callConstant.object());
    // callIntent.setPackage("com.android.phone"); (<= 4.4w)  intent.setPackage("com.android.server.telecom");  (>= 5)
    QAndroidJniObject package;
    if(QtAndroid::androidSdkVersion() >= 21)
        package = QAndroidJniObject::fromString("com.android.server.telecom");
    else
        package = QAndroidJniObject::fromString("com.android.phone");
    callIntent.callObjectMethod("setPackage", "(Ljava/lang/String;)Landroid/content/Intent;", package.object<jstring>());
    // callIntent.setData(Uri.parse("tel:" + number));
    QAndroidJniObject jNumber = QAndroidJniObject::fromString(QString("tel:%1").arg(number));
    QAndroidJniObject uri = QAndroidJniObject::callStaticObjectMethod("android/net/Uri","parse","(Ljava/lang/String;)Landroid/net/Uri;", jNumber.object());
    callIntent.callObjectMethod("setData", "(Landroid/net/Uri;)Landroid/content/Intent;", uri.object<jobject>());
    // callIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    jint flag = QAndroidJniObject::getStaticField<jint>("android/content/Intent", "FLAG_ACTIVITY_NEW_TASK");
    callIntent.callObjectMethod("setFlags", "(I)Landroid/content/Intent;", flag);
    //startActivity(callIntent);
    activity.callMethod<void>("startActivity","(Landroid/content/Intent;)V", callIntent.object<jobject>());
}
    else
        qDebug() << "Something wrong with Qt activity...";
#else
    qDebug() << "Does nothing here...";
#endif
}

As discussed at the beginning, you can include an instance of this class as a context property. The main for this purpose looks like the following:

#include <QApplication>
#include <QQmlContext>
#include <QQmlApplicationEngine>
#include "wrapper.h"

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    QQmlApplicationEngine engine;
    Wrapper jw;
    engine.rootContext()->setContextProperty("caller", &jw);
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));      

    return app.exec();
}

Finally in QML you can simply write:

Button {
    id: callButton
    anchors.centerIn: parent
    text: 'Make a call'
    onClicked: caller.directCall("+0123456789")
}

The code can be easily extended to support also WinPhone while maintaining the same QML interface. Finally, the usage of conditional inclusions guarantees that the code correctly compiles even if the used kit is changed on the fly.

As a final note, I would add that Google Play policies are not as strict as Apple App Store policies. Hence, an app rejection due to the usage of ACTION_CALL is not likely to happen.

这篇关于如何使使用Qt打电话直接从应用程序?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆