├── android
├── res
│ ├── drawable
│ │ └── icon.png
│ └── values
│ │ ├── strings.xml
│ │ └── libs.xml
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ ├── gradle-wrapper.properties~
│ │ └── gradle-wrapper.properties
├── build.gradle
├── gradlew.bat
├── gradlew
└── AndroidManifest.xml
├── qml.qrc
├── source
├── java
│ ├── QuickstartPreferences.java
│ ├── JavaNatives.java
│ ├── MyApplication.java
│ ├── MyGcmListenerService.java
│ ├── RegistrationIntentService.java
│ └── Vibrate.java
├── cpp
│ ├── main.cpp
│ └── misc
│ │ ├── pushnotification.h
│ │ ├── ios
│ │ └── pushnotification.mm
│ │ └── pushnotification.cpp
└── qml
│ └── main.qml
├── .gitignore
├── ios
├── pushnotifications.entitlements
└── Info.plist
├── qtquickcontrols2.conf
├── README.md
├── qt-pushnotifications.pro
└── test_pushnotifications.py
/android/res/drawable/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gympulsr/qt-pushnotifications/HEAD/android/res/drawable/icon.png
--------------------------------------------------------------------------------
/qml.qrc:
--------------------------------------------------------------------------------
1 |
2 |
3 | source/qml/main.qml
4 |
5 |
6 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gympulsr/qt-pushnotifications/HEAD/android/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/source/java/QuickstartPreferences.java:
--------------------------------------------------------------------------------
1 | package com.example.example;
2 |
3 | public class QuickstartPreferences {
4 | public static final String GCM_TOKEN = "";
5 |
6 | }
7 |
--------------------------------------------------------------------------------
/android/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | xxxxxxx
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | qt-pushnotifications.pro.user
3 | apns.pem
4 | android/google-services.json
5 | android/.build
6 | android/gradle.properties
7 | android/gradle.properties~
8 | android/local.properties
9 | android/local.properties~
10 |
--------------------------------------------------------------------------------
/source/java/JavaNatives.java:
--------------------------------------------------------------------------------
1 | //adapt that accordingly
2 | package com.example.example;
3 |
4 | import org.qtproject.qt5.android.QtNative;
5 | import android.content.Intent;
6 |
7 | class JavaNatives{
8 | public static native void sendGCMToken(String gcmToken);
9 | }
10 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties~:
--------------------------------------------------------------------------------
1 | #Wed Apr 10 15:27:10 PDT 2013
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=http\://services.gradle.org/distributions/gradle-1.12-all.zip
7 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Apr 10 15:27:10 PDT 2013
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
7 |
--------------------------------------------------------------------------------
/ios/pushnotifications.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | aps-environment
6 | development
7 |
8 |
9 |
--------------------------------------------------------------------------------
/qtquickcontrols2.conf:
--------------------------------------------------------------------------------
1 | ; This file can be edited to change the style of the application
2 | ; See Styling Qt Quick Controls 2 in the documentation for details:
3 | ; http://doc.qt.io/qt-5/qtquickcontrols2-styles.html
4 |
5 | [Controls]
6 | Style=Default
7 |
8 | [Universal]
9 | Theme=Light
10 | ;Accent=Steel
11 |
12 | [Material]
13 | Theme=Light
14 | ;Accent=BlueGrey
15 | ;Primary=BlueGray
16 |
--------------------------------------------------------------------------------
/source/java/MyApplication.java:
--------------------------------------------------------------------------------
1 | package com.example.example;
2 |
3 | import android.content.Context;
4 |
5 | public class MyApplication extends org.qtproject.qt5.android.bindings.QtApplication
6 | {
7 | private static Context context;
8 |
9 | public void onCreate()
10 | {
11 | super.onCreate();
12 | MyApplication.context = getApplicationContext();
13 | }
14 |
15 | public static Context getAppContext()
16 | {
17 | return MyApplication.context;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/android/res/values/libs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | - https://download.qt.io/ministro/android/qt5/qt-5.7
5 |
6 |
7 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/source/cpp/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include "misc/pushnotification.h"
5 |
6 | int main(int argc, char *argv[])
7 | {
8 | QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
9 | QGuiApplication app(argc, argv);
10 |
11 | qmlRegisterSingletonType("com.example.example", 1, 0, "PushNotificationRegistrationTokenHandler",
12 | PushNotificationRegistrationTokenHandler::pushNotificationRegistrationTokenProvider);
13 |
14 | QQmlApplicationEngine engine;
15 | engine.addImportPath(QStringLiteral("qrc:/"));
16 | engine.load(QUrl(QStringLiteral("qrc:/source/qml/main.qml")));
17 |
18 | return app.exec();
19 | }
20 |
--------------------------------------------------------------------------------
/source/cpp/misc/pushnotification.h:
--------------------------------------------------------------------------------
1 | #ifndef PUSHNOTIFICATION_H
2 | #define PUSHNOTIFICATION_H
3 |
4 | #include
5 | #include
6 |
7 | class PushNotificationRegistrationTokenHandler : public QObject{
8 | Q_OBJECT
9 | Q_PROPERTY(QString gcmRegistrationToken READ getGcmRegistrationToken NOTIFY gcmRegistrationTokenChanged)
10 | Q_PROPERTY(QString apnsRegistrationToken READ getAPNSRegistrationToken WRITE setAPNSRegistrationToken NOTIFY apnsRegistrationTokenChanged)
11 | public:
12 | PushNotificationRegistrationTokenHandler(QObject* parent = 0);
13 | //singleton type provider function for Qt Quick
14 | static QObject* pushNotificationRegistrationTokenProvider(QQmlEngine *engine, QJSEngine *scriptEngine);
15 | //singleton object provider for C++
16 | static PushNotificationRegistrationTokenHandler* instance();
17 | void setGcmRegistrationToken(const QString& gcmRegistrationToken);
18 | QString getGcmRegistrationToken();
19 | QString getAPNSRegistrationToken() const;
20 | void setAPNSRegistrationToken(const QString& apnsToken);
21 | ~PushNotificationRegistrationTokenHandler();
22 | signals:
23 | void gcmRegistrationTokenChanged();
24 | void apnsRegistrationTokenChanged();
25 | void registeredChanged();
26 | private:
27 | QString m_gcmToken;
28 | QString m_apnsToken;
29 | };
30 |
31 |
32 | #endif // PUSHNOTIFICATION_H
33 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # qt-pushnotifications
2 |
3 | This repository demonstrates how to implement push notifications with Qt on iOs and Android.
4 |
5 | For more informations see the following blog entries:
6 |
7 | [iOs push notifications with Qt](https://gympulsr.com/blog/qt/2017/03/08/push-notification-ios-qt.html)
8 |
9 | [Android push notifications with Qt](https://gympulsr.com/blog/qt/2017/03/26/push-notification-android-qt.html)
10 |
11 | About gympulsr
12 | ==============
13 |
14 | gympulsr is a fun community for fitness enthusiasts to connect with like minded people around the world. Mark your gym on a map to connect with people that are working out nearby. Post motivating pictures, show people your gym transformation or just write about your last workout.
15 | Wanna give it a try? Download gympulsr from the Apple or Google Play Store and say hello.
16 |
17 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/qt-pushnotifications.pro:
--------------------------------------------------------------------------------
1 | QT += qml quick
2 |
3 | android{
4 | QT += androidextras
5 | }
6 |
7 | CONFIG += c++11
8 |
9 | SOURCES += \
10 | source/cpp/main.cpp \
11 | source/cpp/misc/pushnotification.cpp
12 |
13 | RESOURCES += qml.qrc
14 |
15 |
16 | ios{
17 | ######## adapt the following value to match your TeamID ########
18 | MY_DEVELOPMENT_TEAM.value = XXXXXXXXX
19 | ################################################################
20 |
21 | MY_DEVELOPMENT_TEAM.name = DEVELOPMENT_TEAM
22 | QMAKE_MAC_XCODE_SETTINGS += MY_DEVELOPMENT_TEAM
23 |
24 | MY_ENTITLEMENTS.name = CODE_SIGN_ENTITLEMENTS
25 | MY_ENTITLEMENTS.value = $$PWD/ios/pushnotifications.entitlements
26 | QMAKE_MAC_XCODE_SETTINGS += MY_ENTITLEMENTS
27 |
28 | QMAKE_IOS_DEPLOYMENT_TARGET=8.0
29 |
30 | # Note for devices: 1=iPhone, 2=iPad, 1,2=Universal.
31 | QMAKE_IOS_TARGETED_DEVICE_FAMILY = 1
32 |
33 | QMAKE_INFO_PLIST = $$PWD/ios/Info.plist
34 |
35 | OBJECTIVE_SOURCES += \
36 | $$PWD/source/cpp/misc/ios/pushnotification.mm \
37 |
38 | CONFIG -= bitcode
39 |
40 | }
41 |
42 | android{
43 | ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android
44 |
45 | ################# adapt that accordingly #######################
46 | ANDROID_JAVA_SOURCES.path = /src/com/example/example
47 | ################################################################
48 |
49 | ANDROID_JAVA_SOURCES.files = $$files($$PWD/source/java/*.java)
50 | INSTALLS += ANDROID_JAVA_SOURCES
51 | }
52 |
53 | HEADERS += \
54 | source/cpp/misc/pushnotification.h
55 |
56 | DISTFILES += \
57 | android/AndroidManifest.xml \
58 | android/gradle/wrapper/gradle-wrapper.jar \
59 | android/gradlew \
60 | android/res/values/libs.xml \
61 | android/build.gradle \
62 | android/gradle/wrapper/gradle-wrapper.properties \
63 | android/gradlew.bat
64 |
--------------------------------------------------------------------------------
/source/qml/main.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.7
2 | import QtQuick.Controls 2.0
3 | import QtQuick.Layouts 1.0
4 | import com.example.example 1.0
5 |
6 | ApplicationWindow {
7 | visible: true
8 | width: 640
9 | height: 480
10 | title: qsTr("Qt Push Notifications Demo")
11 |
12 | Rectangle{
13 | anchors.fill: parent
14 | Text{
15 | id: introduction
16 | anchors.top: parent.top
17 | anchors.horizontalCenter: parent.horizontalCenter
18 | anchors.topMargin: 20
19 | text: "This example demonstrates how to implement push notifications on " + Qt.platform.os;
20 | width: parent.width - 20
21 | wrapMode: Text.WordWrap
22 | }
23 |
24 | Text{
25 | id: registrationToken
26 | anchors.top: introduction.bottom
27 | anchors.horizontalCenter: parent.horizontalCenter
28 | anchors.topMargin: 20
29 | wrapMode: Text.WrapAtWordBoundaryOrAnywhere
30 | width: parent.width - 20
31 | text: Qt.platform.os === "ios" ?
32 | ("Token: " + PushNotificationRegistrationTokenHandler.apnsRegistrationToken)
33 | : ("Token: " + PushNotificationRegistrationTokenHandler.gcmRegistrationToken)
34 | }
35 |
36 | Text{
37 | id: info
38 | anchors.top: registrationToken.bottom
39 | anchors.horizontalCenter: parent.horizontalCenter
40 | anchors.topMargin: 30
41 | wrapMode: Text.WordWrap
42 | width: parent.width - 20
43 | text: "Did you find this example useful? If so, it would really mean a lot to me "
44 | + " if you tell your friends who are into fitness about gympulsr (https://www.gympulsr.com)."
45 | + " Gympulsr is a hobby project of mine that connects fitness enthusiasts around the world with each other"
46 | + " (and btw. it's also written in Qt. ;-)). Thanks a lot!"
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/source/cpp/misc/ios/pushnotification.mm:
--------------------------------------------------------------------------------
1 | #import "UIKit/UIKit.h"
2 | #include "pushnotification.h"
3 |
4 | @interface QIOSApplicationDelegate
5 | @end
6 | //add a category to QIOSApplicationDelegate
7 | @interface QIOSApplicationDelegate (QPushNotificationDelegate)
8 | @end
9 |
10 |
11 | @implementation QIOSApplicationDelegate (QPushNotificationDelegate)
12 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
13 |
14 | //-- Set Notification
15 | if ([application respondsToSelector:@selector(isRegisteredForRemoteNotifications)])
16 | {
17 | // iOS 8 Notifications
18 | [application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge) categories:nil]];
19 |
20 | [application registerForRemoteNotifications];
21 | }
22 | else
23 | {
24 | // iOS < 8 Notifications
25 | [application registerForRemoteNotificationTypes:
26 | (UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound)];
27 | }
28 |
29 | return YES;
30 | }
31 |
32 | - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
33 | NSLog(@"Did Register for Remote Notifications with Device Token (%@)", deviceToken);
34 |
35 | const unsigned *tokenBytes = (const unsigned*)[deviceToken bytes];
36 | NSString *tokenStr = [NSString stringWithFormat:@"%08x%08x%08x%08x%08x%08x%08x%08x",
37 | ntohl(tokenBytes[0]), ntohl(tokenBytes[1]), ntohl(tokenBytes[2]),
38 | ntohl(tokenBytes[3]), ntohl(tokenBytes[4]), ntohl(tokenBytes[5]),
39 | ntohl(tokenBytes[6]), ntohl(tokenBytes[7])];
40 | PushNotificationRegistrationTokenHandler::instance()->setAPNSRegistrationToken(QString::fromNSString(tokenStr));
41 | }
42 |
43 | - (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
44 | NSLog(@"Did Fail to Register for Remote Notifications");
45 | NSLog(@"%@, %@", error, error.localizedDescription);
46 |
47 | }
48 |
49 | @end
50 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | jcenter()
4 | }
5 |
6 | dependencies {
7 | classpath 'com.android.tools.build:gradle:1.1.0'
8 | classpath 'com.google.gms:google-services:3.0.0'
9 | }
10 | }
11 |
12 | allprojects {
13 | repositories {
14 | jcenter()
15 | mavenCentral()
16 | }
17 |
18 | gradle.projectsEvaluated {
19 | tasks.withType(JavaCompile) {
20 | options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation"
21 | }
22 | }
23 | }
24 |
25 | apply plugin: 'com.android.application'
26 |
27 | dependencies {
28 | compile fileTree(dir: 'libs', include: ['*.jar'])
29 | compile "com.google.android.gms:play-services-gcm:9.4.0"
30 | compile "com.android.support:appcompat-v7:22.1.0"
31 | }
32 |
33 | android {
34 | /*******************************************************
35 | * The following variables:
36 | * - androidBuildToolsVersion,
37 | * - androidCompileSdkVersion
38 | * - qt5AndroidDir - holds the path to qt android files
39 | * needed to build any Qt application
40 | * on Android.
41 | *
42 | * are defined in gradle.properties file. This file is
43 | * updated by QtCreator and androiddeployqt tools.
44 | * Changing them manually might break the compilation!
45 | *******************************************************/
46 |
47 | compileSdkVersion androidCompileSdkVersion.toInteger()
48 |
49 | buildToolsVersion androidBuildToolsVersion
50 |
51 | sourceSets {
52 | main {
53 | manifest.srcFile 'AndroidManifest.xml'
54 | java.srcDirs = [qt5AndroidDir + '/src', 'src', 'java']
55 | aidl.srcDirs = [qt5AndroidDir + '/src', 'src', 'aidl']
56 | res.srcDirs = [qt5AndroidDir + '/res', 'res']
57 | resources.srcDirs = ['src']
58 | renderscript.srcDirs = ['src']
59 | assets.srcDirs = ['assets']
60 | jniLibs.srcDirs = ['libs']
61 | }
62 | }
63 |
64 | lintOptions {
65 | abortOnError false
66 | }
67 |
68 | defaultConfig {
69 | //adapt that accordingly
70 | applicationId "com.example.example"
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/test_pushnotifications.py:
--------------------------------------------------------------------------------
1 | from apns2.client import APNsClient
2 | from apns2.payload import Payload
3 | from gcm import GCM
4 | import os
5 |
6 | #####
7 | ## set TARGET to 'android' if you want to send push notifications to android devices
8 | ## set TARGET to 'ios' if you want to send push notifications to iOs devices
9 | TARGET = "ios"
10 |
11 | ###### Set your bundle id
12 | BUNDLE_ID = "com.example.example"
13 |
14 | currentDir = os.path.dirname(os.path.realpath(__file__))
15 |
16 |
17 | if(TARGET == "ios"):
18 | ###### If you are using a production certificate, change this to 'False'
19 | APNS_USE_SANDBOX = True
20 |
21 | ###### set path to APNS certificate
22 | APNS_CERT_PATH = currentDir + os.path.sep + "apns.pem"
23 |
24 | def static_vars(**kwargs):
25 | def decorate(func):
26 | for k in kwargs:
27 | setattr(func, k, kwargs[k])
28 | return func
29 | return decorate
30 |
31 | #creating a connection to the Apple Push notification service is really expensive and furthermore
32 | #has the disadvantage, that Apple detects multiple connection/disconnection attempts as possible DDos attack!
33 | #so we use a static variable to keep the connection open as long as possible.
34 | @static_vars(client=APNsClient('apns.pem', use_sandbox=APNS_USE_SANDBOX, use_alternative_port=False))
35 | def sendAPNSNotification(token, message):
36 | payload = Payload(alert=message, sound="default", badge=0)
37 | #client = APNsClient(APNS_CERT_PATH, use_sandbox=True, use_alternative_port=False)
38 | sendAPNSNotification.client.send_notification(token, payload, topic=BUNDLE_ID)
39 |
40 | elif(TARGET == "android"):
41 | GCM_API_KEY = "YOUR_GCM_API_KEY" #adapt that accordingly
42 |
43 | def sendGCMNotification(registrationTokenList, message):
44 | gcm = GCM(GCM_API_KEY)
45 | #print 'send message to gcm registration ids ' + ', '.join(registrationTokenList)
46 | retVal = gcm.json_request(registration_ids=registrationTokenList, data={"message": message},
47 | delay_while_idle=False)
48 | return retVal
49 |
50 | if __name__ == "__main__":
51 | token = "YOUR_TOKEN" #change that to your token
52 | message = "Hello World"
53 |
54 | print "Sending '%s' to the phone with the token %s" %(message, token,)
55 |
56 | if(TARGET == "ios"):
57 | sendAPNSNotification(token, message)
58 | elif(TARGET == "android"):
59 | sendGCMNotification([token], message)
60 | else:
61 | print "UNKNOWN TARGET"
62 |
63 |
--------------------------------------------------------------------------------
/android/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/source/java/MyGcmListenerService.java:
--------------------------------------------------------------------------------
1 | //adapt that accordingly
2 | package com.example.example;
3 | import com.example.example.R;
4 |
5 | import android.app.NotificationManager;
6 | import android.app.PendingIntent;
7 | import android.content.Context;
8 | import android.content.Intent;
9 | import android.media.RingtoneManager;
10 | import android.net.Uri;
11 | import android.os.Bundle;
12 | import android.support.v4.app.NotificationCompat;
13 | import android.util.Log;
14 |
15 | import com.google.android.gms.gcm.GcmListenerService;
16 |
17 | public class MyGcmListenerService extends GcmListenerService
18 | {
19 | private static final String TAG = "MyGcmListenerService";
20 |
21 | /**
22 | * Called when message is received.
23 | *
24 | * @param from SenderID of the sender.
25 | * @param data Data bundle containing message data as key/value pairs.
26 | * For Set of keys use data.keySet().
27 | */
28 | @Override
29 | public void onMessageReceived(String from, Bundle data)
30 | {
31 | String message = data.getString("message");
32 | Log.d(TAG, "From: " + from);
33 | Log.d(TAG, "Message: " + message);
34 |
35 | //adapt that if you want to react to topics
36 | //individually.
37 | if (from.startsWith("/topics/")) {
38 | // message received from some topic.
39 | } else {
40 | // normal downstream message.
41 | }
42 | /**
43 | * Production applications would usually process the message here.
44 | * Eg: - Syncing with server.
45 | * - Store message in local database.
46 | * - Update UI.
47 | */
48 |
49 | /**
50 | * In some cases it may be useful to show a notification indicating to the user
51 | * that a message was received.
52 | */
53 | sendNotification(message);
54 | }
55 |
56 | /**
57 | * Create and show a simple notification containing the received GCM message.
58 | *
59 | * @param message GCM message received.
60 | */
61 | private void sendNotification(String message)
62 | {
63 | Intent intent = new Intent(this, Vibrate.class);
64 | intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
65 | PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent, PendingIntent.FLAG_ONE_SHOT);
66 |
67 | Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
68 | NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
69 | .setSmallIcon(R.drawable.icon)
70 | .setContentTitle("example") //adapt that accordingly
71 | .setContentText(message)
72 | .setAutoCancel(true)
73 | .setSound(defaultSoundUri)
74 | .setContentIntent(pendingIntent);
75 |
76 | NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
77 |
78 | notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/source/java/RegistrationIntentService.java:
--------------------------------------------------------------------------------
1 | //adapt that accordingly
2 | package com.example.example;
3 |
4 | import android.app.IntentService;
5 | import android.content.Intent;
6 | import android.content.SharedPreferences;
7 | import android.preference.PreferenceManager;
8 | import android.support.v4.content.LocalBroadcastManager;
9 | import android.util.Log;
10 |
11 | import com.google.android.gms.gcm.GcmPubSub;
12 | import com.google.android.gms.gcm.GoogleCloudMessaging;
13 | import com.google.android.gms.iid.InstanceID;
14 |
15 | import java.io.IOException;
16 |
17 | public class RegistrationIntentService extends IntentService {
18 |
19 | private static final String TAG = "RegIntentService";
20 | private static final String[] TOPICS = {"global"};
21 |
22 | public RegistrationIntentService() {
23 | super(TAG);
24 | }
25 |
26 | @Override
27 | protected void onHandleIntent(Intent intent) {
28 | SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
29 |
30 | try {
31 | // [START register_for_gcm]
32 | // Initially this call goes out to the network to retrieve the token, subsequent calls
33 | // are local.
34 | // R.string.gcm_defaultSenderId (the Sender ID) is typically derived from google-services.json.
35 | // See https://developers.google.com/cloud-messaging/android/start for details on this file.
36 | // [START get_token]
37 | InstanceID instanceID = InstanceID.getInstance(this);
38 | String token = instanceID.getToken(getString(R.string.gcm_defaultSenderId),
39 | GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
40 |
41 | // Subscribe to topic channels
42 | subscribeTopics(token);
43 |
44 | sharedPreferences.edit().putString(QuickstartPreferences.GCM_TOKEN, token).apply();
45 |
46 | // You should store a boolean that indicates whether the generated token has been
47 | // sent to your server. If the boolean is false, send the token to your server,
48 | // otherwise your server should have already received the token.
49 | //sharedPreferences.edit().putBoolean(QuickstartPreferences.SENT_TOKEN_TO_SERVER, true).apply();
50 | // [END register_for_gcm]
51 | } catch (Exception e) {
52 | Log.d(TAG, "Failed to complete token refresh", e);
53 | // If an exception happens while fetching the new token or updating our registration data
54 | // on a third-party server, this ensures that we'll attempt the update at a later time.
55 | //sharedPreferences.edit().putBoolean(QuickstartPreferences.SENT_TOKEN_TO_SERVER, false).apply();
56 | }
57 | // Notify UI that registration token has been received
58 | Intent gotToken = new Intent(QuickstartPreferences.GCM_TOKEN);
59 | LocalBroadcastManager.getInstance(this).sendBroadcast(gotToken);
60 | }
61 |
62 |
63 | /**
64 | * Subscribe to any GCM topics of interest, as defined by the TOPICS constant.
65 | *
66 | * @param token GCM token
67 | * @throws IOException if unable to reach the GCM PubSub service
68 | */
69 | private void subscribeTopics(String token) throws IOException {
70 | GcmPubSub pubSub = GcmPubSub.getInstance(this);
71 | for (String topic : TOPICS) {
72 | pubSub.subscribe(token, "/topics/" + topic, null);
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/ios/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDisplayName
6 | ${PRODUCT_NAME}
7 | CFBundleExecutable
8 | qt-pushnotifications
9 | CFBundleGetInfoString
10 | Created by Qt/QMake
11 | CFBundleIconFile
12 |
13 | CFBundleIcons
14 |
15 | CFBundlePrimaryIcon
16 |
17 | CFBundleIconFiles
18 |
19 | AppIcon29x29.png
20 | AppIcon29x29@2x.png
21 | AppIcon40x40@2x.png
22 | AppIcon57x57.png
23 | AppIcon57x57@2x.png
24 | AppIcon60x60@2x.png
25 |
26 |
27 |
28 | CFBundleIdentifier
29 | com.example.example
30 | CFBundleName
31 | ${PRODUCT_NAME}
32 | CFBundlePackageType
33 | APPL
34 | CFBundleShortVersionString
35 | 0.1
36 | CFBundleSignature
37 | ????
38 | CFBundleVersion
39 | 2
40 | ITSAppUsesNonExemptEncryption
41 |
42 | LSRequiresIPhoneOS
43 |
44 | NOTE
45 | This file was generated by Qt/QMake.
46 | UILaunchImageFile
47 | LaunchImage
48 | UILaunchImages
49 |
50 |
51 | UILaunchImageMinimumOSVersion
52 | 7.0
53 | UILaunchImageName
54 | LaunchImage-iOS7
55 | UILaunchImageOrientation
56 | Portrait
57 | UILaunchImageSize
58 | {320, 568}
59 |
60 |
61 | UILaunchImageMinimumOSVersion
62 | 7.0
63 | UILaunchImageName
64 | LaunchImage-iOS7
65 | UILaunchImageOrientation
66 | Portrait
67 | UILaunchImageSize
68 | {320, 480}
69 |
70 |
71 | UILaunchImages~ipad
72 |
73 |
74 | UILaunchImageMinimumOSVersion
75 | 7.0
76 | UILaunchImageName
77 | LaunchImage-iOS7-Portrait
78 | UILaunchImageOrientation
79 | Portrait
80 | UILaunchImageSize
81 | {768, 1024}
82 |
83 |
84 | UILaunchImageMinimumOSVersion
85 | 7.0
86 | UILaunchImageName
87 | LaunchImage-iOS7
88 | UILaunchImageOrientation
89 | Portrait
90 | UILaunchImageSize
91 | {320, 568}
92 |
93 |
94 | UILaunchImageMinimumOSVersion
95 | 7.0
96 | UILaunchImageName
97 | LaunchImage-iOS7
98 | UILaunchImageOrientation
99 | Portrait
100 | UILaunchImageSize
101 | {320, 480}
102 |
103 |
104 | UIRequiresFullScreen
105 |
106 | UISupportedInterfaceOrientations
107 |
108 | UIInterfaceOrientationPortrait
109 | UIInterfaceOrientationPortraitUpsideDown
110 |
111 |
112 |
113 |
--------------------------------------------------------------------------------
/source/cpp/misc/pushnotification.cpp:
--------------------------------------------------------------------------------
1 | #include "pushnotification.h"
2 | #include
3 |
4 | #ifdef Q_OS_ANDROID
5 | #include
6 | #include
7 | #endif
8 |
9 | QString g_gcmRegistrationToken = "";
10 | std::mutex g_RegistrationTokenMutex;
11 |
12 | PushNotificationRegistrationTokenHandler::PushNotificationRegistrationTokenHandler(QObject *parent)
13 | : QObject(parent),
14 | m_gcmToken(""),
15 | m_apnsToken("")
16 | {
17 | }
18 |
19 | QObject* PushNotificationRegistrationTokenHandler::pushNotificationRegistrationTokenProvider(QQmlEngine *engine, QJSEngine *scriptEngine){
20 | Q_UNUSED(engine)
21 | Q_UNUSED(scriptEngine)
22 | return PushNotificationRegistrationTokenHandler::instance();
23 | }
24 |
25 | PushNotificationRegistrationTokenHandler* PushNotificationRegistrationTokenHandler::instance() {
26 | static PushNotificationRegistrationTokenHandler* pushNotificationRegistrationTokenHandler = new PushNotificationRegistrationTokenHandler();
27 | return pushNotificationRegistrationTokenHandler;
28 | }
29 |
30 | void PushNotificationRegistrationTokenHandler::setGcmRegistrationToken(const QString& gcmToken){
31 | m_gcmToken = gcmToken;
32 | }
33 |
34 | QString PushNotificationRegistrationTokenHandler::getGcmRegistrationToken(){
35 | if(g_gcmRegistrationToken != ""){
36 | g_RegistrationTokenMutex.lock();
37 | setGcmRegistrationToken(g_gcmRegistrationToken);
38 | g_gcmRegistrationToken = "";
39 | g_RegistrationTokenMutex.unlock();
40 | }
41 | return m_gcmToken;
42 | }
43 |
44 | QString PushNotificationRegistrationTokenHandler::getAPNSRegistrationToken() const{
45 | return m_apnsToken;
46 | }
47 |
48 | void PushNotificationRegistrationTokenHandler::setAPNSRegistrationToken(const QString& apnsToken){
49 | m_apnsToken = apnsToken;
50 | apnsRegistrationTokenChanged(); //emit signal
51 | }
52 |
53 | PushNotificationRegistrationTokenHandler::~PushNotificationRegistrationTokenHandler(){
54 | }
55 |
56 |
57 |
58 |
59 | #ifdef Q_OS_ANDROID
60 | static void gcmTokenResult(JNIEnv* /*env*/ env, jobject obj, jstring gcmToken)
61 | {
62 | const char* nativeString = env->GetStringUTFChars(gcmToken, 0);
63 | qDebug() << "GCM Token is:" << nativeString;
64 |
65 | //the following is kind of a "hack". We can't use
66 | // PushNotificationRegistrationTokenHandler::instance()->setGcmRegistrationToken(QString(nativeString));
67 | //directly, as this function most probably get's called before the GUI application is initialized. Using a
68 | //QObject before the application is initialized results in undefined behavior and might crash the application.
69 | //So in order to avoid that we are storing the gcm registration token in a global variable. The
70 | //PushNotificationRegistrationTokenHandler::getGcmRegistrationToken() method copies the value in it's own
71 | //private member variable, as soon as the gcm registration token is available.
72 | //Just to be on the safe side, we are protecting the variable with a mutex.
73 | g_RegistrationTokenMutex.lock();
74 | g_gcmRegistrationToken = QString(nativeString);
75 | g_RegistrationTokenMutex.unlock();
76 |
77 | }
78 |
79 |
80 | // create a vector with all our JNINativeMethod(s)
81 | static JNINativeMethod methods[] = {
82 | { "sendGCMToken", // const char* function name;
83 | "(Ljava/lang/String;)V",
84 | (void *)gcmTokenResult // function pointer
85 | }
86 | };
87 |
88 |
89 | // this method is called automatically by Java VM
90 | // after the .so file is loaded
91 | JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* /*reserved*/)
92 | {
93 | JNIEnv* env;
94 | // get the JNIEnv pointer.
95 | if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6)
96 | != JNI_OK) {
97 | return JNI_ERR;
98 | }
99 |
100 | // search for Java class which declares the native methods
101 | jclass javaClass = env->FindClass("com/example/example/JavaNatives");
102 | if (!javaClass)
103 | return JNI_ERR;
104 |
105 | // register our native methods
106 | if (env->RegisterNatives(javaClass, methods,
107 | sizeof(methods) / sizeof(methods[0])) < 0) {
108 | return JNI_ERR;
109 | }
110 |
111 | return JNI_VERSION_1_6;
112 | }
113 | #endif
114 |
--------------------------------------------------------------------------------
/source/java/Vibrate.java:
--------------------------------------------------------------------------------
1 | //adapt that accordingly
2 | package com.example.example;
3 | import com.example.example.R;
4 |
5 | import android.content.Context;
6 | import android.os.Vibrator;
7 | import android.app.Activity;
8 | import android.os.Bundle;
9 |
10 | import android.content.BroadcastReceiver;
11 | import android.content.Intent;
12 | import android.content.IntentFilter;
13 | import android.content.SharedPreferences;
14 | import android.preference.PreferenceManager;
15 | import android.support.v4.content.LocalBroadcastManager;
16 | import android.support.v7.app.AppCompatActivity;
17 | import android.util.Log;
18 | //import android.widget.ProgressBar;
19 | //import android.widget.TextView;
20 |
21 | import com.google.android.gms.common.ConnectionResult;
22 | import com.google.android.gms.common.GoogleApiAvailability;
23 |
24 | public class Vibrate extends org.qtproject.qt5.android.bindings.QtActivity
25 | {
26 | // start GCM
27 | private static final int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;
28 | private static final String TAG = "MainActivity";
29 |
30 | private BroadcastReceiver mRegistrationBroadcastReceiver;
31 | //private KeyStore m_keyStore;
32 |
33 | @Override
34 | public void onCreate(Bundle savedInstanceState)
35 | {
36 | super.onCreate(savedInstanceState);
37 |
38 | mRegistrationBroadcastReceiver = new BroadcastReceiver()
39 | {
40 | @Override
41 | public void onReceive(Context context, Intent intent)
42 | {
43 | SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
44 | String token = sharedPreferences.getString(QuickstartPreferences.GCM_TOKEN, "");
45 | Log.i("Activity", token);
46 | JavaNatives.sendGCMToken(token);
47 | }
48 | };
49 |
50 | if (checkPlayServices())
51 | {
52 | // Start IntentService to register this application with GCM.
53 | Intent intent = new Intent(this, RegistrationIntentService.class);
54 | startService(intent);
55 | }
56 | }
57 |
58 | @Override
59 | protected void onResume()
60 | {
61 | super.onResume();
62 | LocalBroadcastManager.getInstance(this).registerReceiver(mRegistrationBroadcastReceiver,
63 | new IntentFilter(QuickstartPreferences.GCM_TOKEN));
64 | }
65 |
66 | @Override
67 | protected void onSaveInstanceState(Bundle outState) {
68 | super.onSaveInstanceState(outState);
69 | }
70 |
71 | @Override
72 | protected void onPause()
73 | {
74 | LocalBroadcastManager.getInstance(this).unregisterReceiver(mRegistrationBroadcastReceiver);
75 | super.onPause();
76 | }
77 |
78 | //
79 | // Check the device to make sure it has the Google Play Services APK. If
80 | // it doesn't, display a dialog that allows users to download the APK from
81 | // the Google Play Store or enable it in the device's system settings.
82 | //
83 | private boolean checkPlayServices()
84 | {
85 | GoogleApiAvailability apiAvailability = GoogleApiAvailability.getInstance();
86 | int resultCode = apiAvailability.isGooglePlayServicesAvailable(this);
87 | if (resultCode != ConnectionResult.SUCCESS)
88 | {
89 | if (apiAvailability.isUserResolvableError(resultCode))
90 | {
91 | apiAvailability.getErrorDialog(this, resultCode, PLAY_SERVICES_RESOLUTION_REQUEST).show();
92 | }
93 | else
94 | {
95 | Log.i(TAG, "This device is not supported.");
96 | finish();
97 | }
98 | return false;
99 | }
100 | return true;
101 | }
102 |
103 |
104 |
105 | // start vibrate
106 | public static Vibrator m_vibrator;
107 | public static Vibrate m_istance;
108 | public Vibrate()
109 | {
110 | m_istance = this;
111 | }
112 | public static void start(int x)
113 | {
114 | if (m_vibrator == null)
115 | {
116 | if (m_istance != null)
117 | {
118 | m_vibrator = (Vibrator) m_istance.getSystemService(Context.VIBRATOR_SERVICE);
119 | m_vibrator.vibrate(x);
120 | }
121 | }
122 | else m_vibrator.vibrate(x);
123 | }
124 | // end vibrate
125 |
126 | }
127 |
--------------------------------------------------------------------------------
/android/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/android/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
10 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
24 |
25 |
26 |
27 |
32 |
34 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
85 |
86 |
89 |
90 |
91 |
92 |
93 |
94 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
117 |
118 |
119 |
120 |
121 |
--------------------------------------------------------------------------------