Browse Source

Android: fix PushNotifications that got broken by Android low level code rework.

tags/2021-05-28
Lukasz Kozakiewicz 6 years ago
parent
commit
7c4601473a
22 changed files with 356 additions and 123 deletions
  1. +14
    -16
      examples/Assets/google-services.json
  2. +1
    -1
      examples/DemoRunner/Builds/Android/app/CMakeLists.txt
  3. +2
    -1
      examples/DemoRunner/Builds/Android/app/build.gradle
  4. +1
    -1
      examples/DemoRunner/Builds/Android/app/src/main/AndroidManifest.xml
  5. +14
    -16
      examples/DemoRunner/Builds/Android/app/src/main/assets/google-services.json
  6. BIN
      examples/DemoRunner/Builds/Android/app/src/main/assets/juce_icon_template.png
  7. +94
    -6
      examples/Utilities/PushNotificationsDemo.h
  8. +1
    -1
      extras/AudioPerformanceTest/Builds/Android/app/CMakeLists.txt
  9. +2
    -1
      extras/AudioPerformanceTest/Builds/Android/app/build.gradle
  10. +1
    -1
      extras/AudioPerformanceTest/Builds/Android/app/src/main/AndroidManifest.xml
  11. +1
    -1
      extras/AudioPluginHost/Builds/Android/app/CMakeLists.txt
  12. +2
    -1
      extras/AudioPluginHost/Builds/Android/app/build.gradle
  13. +1
    -1
      extras/AudioPluginHost/Builds/Android/app/src/main/AndroidManifest.xml
  14. +1
    -1
      extras/NetworkGraphicsDemo/Builds/Android/app/CMakeLists.txt
  15. +2
    -1
      extras/NetworkGraphicsDemo/Builds/Android/app/build.gradle
  16. +1
    -1
      extras/NetworkGraphicsDemo/Builds/Android/app/src/main/AndroidManifest.xml
  17. +46
    -25
      extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Android.h
  18. +20
    -0
      modules/juce_gui_basics/native/javaopt/app/com/roli/juce/JuceActivity.java
  19. +3
    -5
      modules/juce_gui_extra/misc/juce_PushNotifications.h
  20. +16
    -0
      modules/juce_gui_extra/native/javaopt/app/com/roli/juce/JuceFirebaseInstanceIdService.java
  21. +35
    -0
      modules/juce_gui_extra/native/javaopt/app/com/roli/juce/JuceFirebaseMessagingService.java
  22. +98
    -43
      modules/juce_gui_extra/native/juce_android_PushNotifications.cpp

+ 14
- 16
examples/Assets/google-services.json View File

@@ -1,39 +1,37 @@
{
"project_info": {
"project_number": "3137221487",
"firebase_url": "https://pushnotificationsdemo-1c714.firebaseio.com",
"project_id": "pushnotificationsdemo-1c714",
"storage_bucket": "pushnotificationsdemo-1c714.appspot.com"
"project_number": "50526851168",
"firebase_url": "https://pushnotificationsdemorunner.firebaseio.com",
"project_id": "pushnotificationsdemorunner",
"storage_bucket": "pushnotificationsdemorunner.appspot.com"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:3137221487:android:8fdcd861a33b035c",
"mobilesdk_app_id": "1:50526851168:android:6fa3f0d4b79f1940",
"android_client_info": {
"package_name": "com.juce.pushnotificationsdemo"
"package_name": "com.juce.demorunner"
}
},
"oauth_client": [
{
"client_id": "3137221487-uftk61ukltbi07dmejslgt0d6qnml0oo.apps.googleusercontent.com",
"client_id": "50526851168-vgn4rv0vimpc8kdm7ecmb3g95t1et0t5.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyDPpqphjiEEYI3sJGptrebN5Z52GkOG4Wo"
"current_key": "AIzaSyAMwLOFACFo7_SHm9iiVhoa0zCjFyMsgFc"
}
],
"services": {
"analytics_service": {
"status": 1
},
"appinvite_service": {
"status": 1,
"other_platform_oauth_client": []
},
"ads_service": {
"status": 2
"other_platform_oauth_client": [
{
"client_id": "50526851168-vgn4rv0vimpc8kdm7ecmb3g95t1et0t5.apps.googleusercontent.com",
"client_type": 3
}
]
}
}
}


+ 1
- 1
examples/DemoRunner/Builds/Android/app/CMakeLists.txt View File

@@ -8,7 +8,7 @@ SET(BINARY_NAME "juce_jni")
add_library("cpufeatures" STATIC "${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c")
set_source_files_properties("${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c" PROPERTIES COMPILE_FLAGS "-Wno-sign-conversion -Wno-gnu-statement-expression")

add_definitions("-DJUCE_ANDROID=1" "-DJUCE_ANDROID_API_VERSION=23" "-DJUCE_PUSH_NOTIFICATIONS=1" "-DJUCE_ANDROID_GL_ES_VERSION_3_0=1" "-DJUCE_DEMO_RUNNER=1" "-DJUCE_UNIT_TESTS=1" "-DJUCER_ANDROIDSTUDIO_7F0E4A25=1" "-DJUCE_APP_VERSION=5.4.3" "-DJUCE_APP_VERSION_HEX=0x50403")
add_definitions("-DJUCE_ANDROID=1" "-DJUCE_ANDROID_API_VERSION=23" "-DJUCE_PUSH_NOTIFICATIONS=1" "-DJUCE_PUSH_NOTIFICATIONS_ACTIVITY=\"com/roli/juce/JuceActivity\"" "-DJUCE_ANDROID_GL_ES_VERSION_3_0=1" "-DJUCE_DEMO_RUNNER=1" "-DJUCE_UNIT_TESTS=1" "-DJUCER_ANDROIDSTUDIO_7F0E4A25=1" "-DJUCE_APP_VERSION=5.4.3" "-DJUCE_APP_VERSION_HEX=0x50403")

include_directories( AFTER
"../../../JuceLibraryCode"


+ 2
- 1
examples/DemoRunner/Builds/Android/app/build.gradle View File

@@ -86,7 +86,8 @@ android {
main.java.srcDirs +=
["../../../../../modules/juce_core/native/javacore/init",
"../../../../../modules/juce_core/native/javacore/app",
"../../../../../modules/juce_gui_basics/native/javacore/app"]
"../../../../../modules/juce_gui_basics/native/javacore/app",
"../../../../../modules/juce_gui_basics/native/javaopt/app"]

main.res.srcDirs +=
[]


+ 1
- 1
examples/DemoRunner/Builds/Android/app/src/main/AndroidManifest.xml View File

@@ -13,7 +13,7 @@
<uses-permission android:name="android.permission.INTERNET"/>
<uses-feature android:glEsVersion="0x00030000" android:required="true"/>
<application android:label="@string/app_name" android:name="com.roli.juce.JuceApp" android:icon="@drawable/icon" android:hardwareAccelerated="false">
<activity android:name="android.app.Activity" android:label="@string/app_name" android:configChanges="keyboardHidden|orientation|screenSize"
<activity android:name="com.roli.juce.JuceActivity" android:label="@string/app_name" android:configChanges="keyboardHidden|orientation|screenSize"
android:screenOrientation="unspecified" android:launchMode="singleTask" android:hardwareAccelerated="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>


+ 14
- 16
examples/DemoRunner/Builds/Android/app/src/main/assets/google-services.json View File

@@ -1,39 +1,37 @@
{
"project_info": {
"project_number": "3137221487",
"firebase_url": "https://pushnotificationsdemo-1c714.firebaseio.com",
"project_id": "pushnotificationsdemo-1c714",
"storage_bucket": "pushnotificationsdemo-1c714.appspot.com"
"project_number": "50526851168",
"firebase_url": "https://pushnotificationsdemorunner.firebaseio.com",
"project_id": "pushnotificationsdemorunner",
"storage_bucket": "pushnotificationsdemorunner.appspot.com"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:3137221487:android:8fdcd861a33b035c",
"mobilesdk_app_id": "1:50526851168:android:6fa3f0d4b79f1940",
"android_client_info": {
"package_name": "com.juce.pushnotificationsdemo"
"package_name": "com.juce.demorunner"
}
},
"oauth_client": [
{
"client_id": "3137221487-uftk61ukltbi07dmejslgt0d6qnml0oo.apps.googleusercontent.com",
"client_id": "50526851168-vgn4rv0vimpc8kdm7ecmb3g95t1et0t5.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyDPpqphjiEEYI3sJGptrebN5Z52GkOG4Wo"
"current_key": "AIzaSyAMwLOFACFo7_SHm9iiVhoa0zCjFyMsgFc"
}
],
"services": {
"analytics_service": {
"status": 1
},
"appinvite_service": {
"status": 1,
"other_platform_oauth_client": []
},
"ads_service": {
"status": 2
"other_platform_oauth_client": [
{
"client_id": "50526851168-vgn4rv0vimpc8kdm7ecmb3g95t1et0t5.apps.googleusercontent.com",
"client_type": 3
}
]
}
}
}


BIN
examples/DemoRunner/Builds/Android/app/src/main/assets/juce_icon_template.png View File

Before After
Width: 512  |  Height: 512  |  Size: 18KB

+ 94
- 6
examples/Utilities/PushNotificationsDemo.h View File

@@ -51,6 +51,74 @@
#include "../Assets/DemoUtilities.h"
/*
To finish the setup of this demo, do the following:
1. Download google_services.json from your Firebase project.
2. Update "Remote Notifications Config File" path in Android exporter (this can be different for debug and release)
to point to that json file.
3. Add image and sound resources by adding the following to "Extra Android Raw Resources" in Projucer:
../../Assets/Notifications/images/ic_stat_name.png
../../Assets/Notifications/images/ic_stat_name2.png
../../Assets/Notifications/images/ic_stat_name3.png
../../Assets/Notifications/images/ic_stat_name4.png
../../Assets/Notifications/images/ic_stat_name5.png
../../Assets/Notifications/images/ic_stat_name6.png
../../Assets/Notifications/images/ic_stat_name7.png
../../Assets/Notifications/images/ic_stat_name8.png
../../Assets/Notifications/images/ic_stat_name9.png
../../Assets/Notifications/images/ic_stat_name10.png
../../Assets/Notifications/sounds/demonstrative.mp3
../../Assets/Notifications/sounds/isntit.mp3
../../Assets/Notifications/sounds/jinglebellssms.mp3
../../Assets/Notifications/sounds/served.mp3
../../Assets/Notifications/sounds/solemn.mp3
4. Set "Remote Notifications" to enabled in Projucer Android exporter.
To verify that remote notifications are configured properly, go to Remote tab in the demo and press "GetDeviceToken"
button, a dialog with your token (also printed to console in debug build) should show up.
The following steps are only necessary if you have a custom activity defined:
5. Ensure that its launchMode is set to "singleTop" or "singleTask" in Android manifest. This is the default behaviour
in JUCE so you only need to do it if you have custom Android manifest content. You can do it from Projucer by
ensuring that "Custom Manifest XML Content" contains:
<manifest>
<application>
<activity android:launchMode="singleTask">
</activity>
</application>
</manifest>
6. Ensure that you override onNewIntent() function in the same way as it is done in JuceActivity.java:
package com.roli.juce;
import android.app.Activity;
import android.content.Intent;
//==============================================================================
public class JuceActivity extends Activity
{
//==============================================================================
private native void appNewIntent (Intent intent);
@Override
protected void onNewIntent (Intent intent)
{
super.onNewIntent(intent);
setIntent(intent);
appNewIntent (intent);
}
}
*/
//==============================================================================
class PushNotificationsDemo : public Component,
private ChangeListener,
@@ -101,11 +169,11 @@ public:
#endif
sendButton.onClick = [this] { sendLocalNotification(); };
auxActionsView.getDeliveredNotificationsButton .onClick = [this]
auxActionsView.getDeliveredNotificationsButton .onClick = []
{ PushNotifications::getInstance()->getDeliveredNotifications(); };
auxActionsView.removeDeliveredNotifWithIdButton.onClick = [this]
{ PushNotifications::getInstance()->removeDeliveredNotification (auxActionsView.deliveredNotifIdentifier.getText()); };
auxActionsView.removeAllDeliveredNotifsButton .onClick = [this]
auxActionsView.removeAllDeliveredNotifsButton .onClick = []
{ PushNotifications::getInstance()->removeAllDeliveredNotifications(); };
#if JUCE_IOS || JUCE_MAC
auxActionsView.getPendingNotificationsButton .onClick = [this]
@@ -116,7 +184,7 @@ public:
{ PushNotifications::getInstance()->removeAllPendingLocalNotifications(); };
#endif
remoteView.getDeviceTokenButton.onClick = [this]
remoteView.getDeviceTokenButton.onClick = []
{
String token = PushNotifications::getInstance()->getDeviceToken();
@@ -129,7 +197,7 @@ public:
};
#if JUCE_ANDROID
remoteView.sendRemoteMessageButton.onClick = [this]
remoteView.sendRemoteMessageButton.onClick = []
{
StringPairArray data;
data.set ("key1", "value1");
@@ -144,9 +212,9 @@ public:
data);
};
remoteView.subscribeToSportsButton .onClick = [this]
remoteView.subscribeToSportsButton .onClick = []
{ PushNotifications::getInstance()->subscribeToTopic ("sports"); };
remoteView.unsubscribeFromSportsButton.onClick = [this]
remoteView.unsubscribeFromSportsButton.onClick = []
{ PushNotifications::getInstance()->unsubscribeFromTopic ("sports"); };
#endif
@@ -164,11 +232,31 @@ public:
PushNotifications::ChannelGroup cg { "demoGroup", "demo group" };
PushNotifications::getInstance()->setupChannels ({ { cg } }, getAndroidChannels());
#endif
#if JUCE_IOS || JUCE_ANDROID
setPortraitOrientationEnabled (true);
#endif
}
~PushNotificationsDemo()
{
PushNotifications::getInstance()->removeListener (this);
#if JUCE_IOS || JUCE_ANDROID
setPortraitOrientationEnabled (false);
#endif
}
void setPortraitOrientationEnabled (bool shouldBeEnabled)
{
auto allowedOrientations = Desktop::getInstance().getOrientationsEnabled();
if (shouldBeEnabled)
allowedOrientations |= Desktop::upright;
else
allowedOrientations &= ~Desktop::upright;
Desktop::getInstance().setOrientationsEnabled (allowedOrientations);
}
void paint (Graphics& g) override


+ 1
- 1
extras/AudioPerformanceTest/Builds/Android/app/CMakeLists.txt View File

@@ -8,7 +8,7 @@ SET(BINARY_NAME "juce_jni")
add_library("cpufeatures" STATIC "${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c")
set_source_files_properties("${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c" PROPERTIES COMPILE_FLAGS "-Wno-sign-conversion -Wno-gnu-statement-expression")

add_definitions("-DJUCE_ANDROID=1" "-DJUCE_ANDROID_API_VERSION=23" "-DJUCE_PUSH_NOTIFICATIONS=1" "-DJUCE_ANDROID_GL_ES_VERSION_3_0=1" "-DJUCER_ANDROIDSTUDIO_7F0E4A25=1" "-DJUCE_APP_VERSION=1.0.0" "-DJUCE_APP_VERSION_HEX=0x10000")
add_definitions("-DJUCE_ANDROID=1" "-DJUCE_ANDROID_API_VERSION=23" "-DJUCE_PUSH_NOTIFICATIONS=1" "-DJUCE_PUSH_NOTIFICATIONS_ACTIVITY=\"com/roli/juce/JuceActivity\"" "-DJUCE_ANDROID_GL_ES_VERSION_3_0=1" "-DJUCER_ANDROIDSTUDIO_7F0E4A25=1" "-DJUCE_APP_VERSION=1.0.0" "-DJUCE_APP_VERSION_HEX=0x10000")

include_directories( AFTER
"../../../JuceLibraryCode"


+ 2
- 1
extras/AudioPerformanceTest/Builds/Android/app/build.gradle View File

@@ -89,7 +89,8 @@ android {
main.java.srcDirs +=
["../../../../../modules/juce_core/native/javacore/init",
"../../../../../modules/juce_core/native/javacore/app",
"../../../../../modules/juce_gui_basics/native/javacore/app"]
"../../../../../modules/juce_gui_basics/native/javacore/app",
"../../../../../modules/juce_gui_basics/native/javaopt/app"]

main.res.srcDirs +=
[]


+ 1
- 1
extras/AudioPerformanceTest/Builds/Android/app/src/main/AndroidManifest.xml View File

@@ -10,7 +10,7 @@
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.INTERNET"/>
<application android:label="@string/app_name" android:name="com.roli.juce.JuceApp" android:hardwareAccelerated="false">
<activity android:name="android.app.Activity" android:label="@string/app_name" android:configChanges="keyboardHidden|orientation|screenSize"
<activity android:name="com.roli.juce.JuceActivity" android:label="@string/app_name" android:configChanges="keyboardHidden|orientation|screenSize"
android:screenOrientation="unspecified" android:launchMode="singleTask" android:hardwareAccelerated="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>


+ 1
- 1
extras/AudioPluginHost/Builds/Android/app/CMakeLists.txt View File

@@ -8,7 +8,7 @@ SET(BINARY_NAME "juce_jni")
add_library("cpufeatures" STATIC "${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c")
set_source_files_properties("${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c" PROPERTIES COMPILE_FLAGS "-Wno-sign-conversion -Wno-gnu-statement-expression")

add_definitions("-DJUCE_ANDROID=1" "-DJUCE_ANDROID_API_VERSION=23" "-DJUCE_PUSH_NOTIFICATIONS=1" "-DJUCE_ANDROID_GL_ES_VERSION_3_0=1" "-DJUCER_ANDROIDSTUDIO_7F0E4A25=1" "-DJUCE_APP_VERSION=1.0.0" "-DJUCE_APP_VERSION_HEX=0x10000")
add_definitions("-DJUCE_ANDROID=1" "-DJUCE_ANDROID_API_VERSION=23" "-DJUCE_PUSH_NOTIFICATIONS=1" "-DJUCE_PUSH_NOTIFICATIONS_ACTIVITY=\"com/roli/juce/JuceActivity\"" "-DJUCE_ANDROID_GL_ES_VERSION_3_0=1" "-DJUCER_ANDROIDSTUDIO_7F0E4A25=1" "-DJUCE_APP_VERSION=1.0.0" "-DJUCE_APP_VERSION_HEX=0x10000")

include_directories( AFTER
"../../../../../modules/juce_audio_processors/format_types/VST3_SDK"


+ 2
- 1
extras/AudioPluginHost/Builds/Android/app/build.gradle View File

@@ -86,7 +86,8 @@ android {
main.java.srcDirs +=
["../../../../../modules/juce_core/native/javacore/init",
"../../../../../modules/juce_core/native/javacore/app",
"../../../../../modules/juce_gui_basics/native/javacore/app"]
"../../../../../modules/juce_gui_basics/native/javacore/app",
"../../../../../modules/juce_gui_basics/native/javaopt/app"]

main.res.srcDirs +=
[]


+ 1
- 1
extras/AudioPluginHost/Builds/Android/app/src/main/AndroidManifest.xml View File

@@ -12,7 +12,7 @@
<uses-permission android:name="android.permission.INTERNET"/>
<uses-feature android:glEsVersion="0x00030000" android:required="true"/>
<application android:label="@string/app_name" android:name="com.roli.juce.JuceApp" android:icon="@drawable/icon" android:hardwareAccelerated="false">
<activity android:name="android.app.Activity" android:label="@string/app_name" android:configChanges="keyboardHidden|orientation|screenSize"
<activity android:name="com.roli.juce.JuceActivity" android:label="@string/app_name" android:configChanges="keyboardHidden|orientation|screenSize"
android:screenOrientation="unspecified" android:launchMode="singleTask" android:hardwareAccelerated="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>


+ 1
- 1
extras/NetworkGraphicsDemo/Builds/Android/app/CMakeLists.txt View File

@@ -8,7 +8,7 @@ SET(BINARY_NAME "juce_jni")
add_library("cpufeatures" STATIC "${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c")
set_source_files_properties("${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c" PROPERTIES COMPILE_FLAGS "-Wno-sign-conversion -Wno-gnu-statement-expression")

add_definitions("-DJUCE_ANDROID=1" "-DJUCE_ANDROID_API_VERSION=16" "-DJUCE_PUSH_NOTIFICATIONS=1" "-DJUCER_ANDROIDSTUDIO_7F0E4A25=1" "-DJUCE_APP_VERSION=1.0.0" "-DJUCE_APP_VERSION_HEX=0x10000")
add_definitions("-DJUCE_ANDROID=1" "-DJUCE_ANDROID_API_VERSION=16" "-DJUCE_PUSH_NOTIFICATIONS=1" "-DJUCE_PUSH_NOTIFICATIONS_ACTIVITY=\"com/roli/juce/JuceActivity\"" "-DJUCER_ANDROIDSTUDIO_7F0E4A25=1" "-DJUCE_APP_VERSION=1.0.0" "-DJUCE_APP_VERSION_HEX=0x10000")

include_directories( AFTER
"../../../JuceLibraryCode"


+ 2
- 1
extras/NetworkGraphicsDemo/Builds/Android/app/build.gradle View File

@@ -86,7 +86,8 @@ android {
main.java.srcDirs +=
["../../../../../modules/juce_core/native/javacore/init",
"../../../../../modules/juce_core/native/javacore/app",
"../../../../../modules/juce_gui_basics/native/javacore/app"]
"../../../../../modules/juce_gui_basics/native/javacore/app",
"../../../../../modules/juce_gui_basics/native/javaopt/app"]

main.res.srcDirs +=
[]


+ 1
- 1
extras/NetworkGraphicsDemo/Builds/Android/app/src/main/AndroidManifest.xml View File

@@ -11,7 +11,7 @@
<uses-permission android:name="android.permission.INTERNET"/>
<uses-feature android:glEsVersion="0x00020000" android:required="true"/>
<application android:label="@string/app_name" android:name="com.roli.juce.JuceApp" android:icon="@drawable/icon" android:hardwareAccelerated="false">
<activity android:name="android.app.Activity" android:label="@string/app_name" android:configChanges="keyboardHidden|orientation|screenSize"
<activity android:name="com.roli.juce.JuceActivity" android:label="@string/app_name" android:configChanges="keyboardHidden|orientation|screenSize"
android:screenOrientation="unspecified" android:launchMode="singleTask" android:hardwareAccelerated="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>


+ 46
- 25
extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Android.h View File

@@ -84,6 +84,8 @@ public:
static const char* getName() { return "Android"; }
static const char* getValueTreeTypeName() { return "ANDROIDSTUDIO"; }
static const char* getDefaultActivityClass() { return "com.roli.juce.JuceActivity"; }
static const char* getDefaultApplicationClass() { return "com.roli.juce.JuceApp"; }
static AndroidProjectExporter* createForSettings (Project& project, const ValueTree& settings)
{
@@ -98,7 +100,7 @@ public:
androidCustomActivityClass, androidCustomApplicationClass, androidManifestCustomXmlElements, androidVersionCode,
androidMinimumSDK, androidTargetSDK, androidTheme, androidSharedLibraries, androidStaticLibraries, androidExtraAssetsFolder,
androidOboeRepositoryPath, androidInternetNeeded, androidMicNeeded, androidCameraNeeded, androidBluetoothNeeded, androidExternalReadPermission,
androidExternalWritePermission, androidInAppBillingPermission, androidVibratePermission,androidOtherPermissions,
androidExternalWritePermission, androidInAppBillingPermission, androidVibratePermission, androidOtherPermissions,
androidEnableRemoteNotifications, androidRemoteNotificationsConfigFile, androidEnableContentSharing, androidKeyStore,
androidKeyStorePass, androidKeyAlias, androidKeyAliasPass, gradleVersion, gradleToolchain, androidPluginVersion;
@@ -111,8 +113,8 @@ public:
androidRepositories (settings, Ids::androidRepositories, getUndoManager()),
androidDependencies (settings, Ids::androidDependencies, getUndoManager()),
androidScreenOrientation (settings, Ids::androidScreenOrientation, getUndoManager(), "unspecified"),
androidCustomActivityClass (settings, Ids::androidCustomActivityClass, getUndoManager()),
androidCustomApplicationClass (settings, Ids::androidCustomApplicationClass, getUndoManager(), "com.roli.juce.JuceApp"),
androidCustomActivityClass (settings, Ids::androidCustomActivityClass, getUndoManager(), getDefaultActivityClass()),
androidCustomApplicationClass (settings, Ids::androidCustomApplicationClass, getUndoManager(), getDefaultApplicationClass()),
androidManifestCustomXmlElements (settings, Ids::androidManifestCustomXmlElements, getUndoManager()),
androidVersionCode (settings, Ids::androidVersionCode, getUndoManager(), "1"),
androidMinimumSDK (settings, Ids::androidMinimumSDK, getUndoManager(), "16"),
@@ -570,7 +572,7 @@ private:
mo << " classpath 'com.android.tools.build:gradle:" << androidPluginVersion.get().toString() << "'" << newLine;
if (androidEnableRemoteNotifications.get())
mo << " classpath 'com.google.gms:google-services:3.1.0'" << newLine;
mo << " classpath 'com.google.gms:google-services:4.0.1'" << newLine;
mo << " }" << newLine;
mo << "}" << newLine;
@@ -814,8 +816,8 @@ private:
if (androidEnableRemoteNotifications.get())
{
mo << " 'com.google.firebase:firebase-core:11.4.0'" << newLine;
mo << " compile 'com.google.firebase:firebase-messaging:11.4.0'" << newLine;
mo << " implementation 'com.google.firebase:firebase-core:16.0.1'" << newLine;
mo << " implementation 'com.google.firebase:firebase-messaging:17.6.0'" << newLine;
}
mo << " }" << newLine;
@@ -834,17 +836,32 @@ private:
return mo.toString();
}
void addModuleJavaFolderToSourceSet(StringArray& javaSourceSets, const File& javacore) const
void addModuleJavaFolderToSourceSet(StringArray& javaSourceSets, const File& source) const
{
if (javacore.isDirectory())
if (source.isDirectory())
{
auto appFolder = getTargetFolder().getChildFile ("app");
RelativePath relativePath (javacore, appFolder, RelativePath::buildTargetFolder);
RelativePath relativePath (source, appFolder, RelativePath::buildTargetFolder);
javaSourceSets.add (relativePath.toUnixStyle());
}
}
void addOptJavaFolderToSourceSetsForModule (StringArray& javaSourceSets,
const OwnedArray<LibraryModule>& modules,
const String& moduleID) const
{
for (auto& m : modules)
{
if (m->getID() == moduleID)
{
auto javaFolder = m->getFolder().getChildFile ("native").getChildFile ("javaopt");
addModuleJavaFolderToSourceSet (javaSourceSets, javaFolder.getChildFile("app"));
return;
}
}
}
String getAndroidJavaSourceSets (const OwnedArray<LibraryModule>& modules) const
{
auto javaSourceSets = getSourceSetArrayFor (androidAdditionalJavaFolders.get().toString());
@@ -860,6 +877,12 @@ private:
addModuleJavaFolderToSourceSet (javaSourceSets, javaFolder.getChildFile("app"));
}
if (androidCustomActivityClass.get() == getDefaultActivityClass())
addOptJavaFolderToSourceSetsForModule (javaSourceSets, modules, "juce_gui_basics");
if (androidEnableRemoteNotifications.get())
addOptJavaFolderToSourceSetsForModule (javaSourceSets, modules, "juce_gui_extra");
MemoryOutputStream mo;
mo.setNewLineString ("\n");
@@ -974,7 +997,9 @@ private:
props.add (new TextPropertyComponent (androidCustomActivityClass, "Custom Android Activity", 256, false),
"If not empty, specifies the Android Activity class name stored in the app's manifest which "
"should be used instead of Android's default Activity.");
"should be used instead of default com.roli.juce.JuceActivity. If you specify a custom Activity "
"then you should implement onNewIntent() function like the one in com.roli.juce.JuceActivity, if "
"you wish to be able to handle push notification events.");
props.add (new TextPropertyComponent (androidCustomApplicationClass, "Custom Android Application", 256, false),
"If not empty, specifies the Android Application class name stored in the app's manifest which "
@@ -1135,19 +1160,8 @@ private:
}
}
String getActivityClass() const
{
auto customActivityClass = androidCustomActivityClass.get().toString();
return (customActivityClass.isEmpty()) ? "android.app.Activity" : customActivityClass;
}
String getApplicationClass() const
{
auto customApplicationClass = androidCustomApplicationClass.get().toString();
return (customApplicationClass.isEmpty()) ? "com.roli.juce.JuceApp" : customApplicationClass;
}
String getActivityClass() const { return androidCustomActivityClass.get(); }
String getApplicationClass() const { return androidCustomApplicationClass.get(); }
String getJNIActivityClassName() const
{
@@ -1374,6 +1388,7 @@ private:
defines.set ("JUCE_ANDROID", "1");
defines.set ("JUCE_ANDROID_API_VERSION", androidMinimumSDK.get());
defines.set ("JUCE_PUSH_NOTIFICATIONS", "1");
defines.set ("JUCE_PUSH_NOTIFICATIONS_ACTIVITY", String::formatted("\"%s\"", getJNIActivityClassName().toUTF8()));
if (androidInAppBillingPermission.get())
defines.set ("JUCE_IN_APP_PURCHASES", "1");
@@ -1381,6 +1396,12 @@ private:
if (supportsGLv3())
defines.set ("JUCE_ANDROID_GL_ES_VERSION_3_0", "1");
if (androidEnableRemoteNotifications.get())
{
defines.set ("JUCE_FIREBASE_INSTANCE_ID_SERVICE_CLASSNAME", "com_roli_juce_JuceFirebaseInstanceIdService");
defines.set ("JUCE_FIREBASE_MESSAGING_SERVICE_CLASSNAME", "com_roli_juce_JuceFirebaseMessagingService");
}
return defines;
}
@@ -1683,12 +1704,12 @@ private:
if (androidEnableRemoteNotifications.get())
{
auto* service = application.createNewChildElement ("service");
service->setAttribute ("android:name", ".JuceFirebaseMessagingService");
service->setAttribute ("android:name", "com.roli.juce.JuceFirebaseMessagingService");
auto* intentFilter = service->createNewChildElement ("intent-filter");
intentFilter->createNewChildElement ("action")->setAttribute ("android:name", "com.google.firebase.MESSAGING_EVENT");
service = application.createNewChildElement ("service");
service->setAttribute ("android:name", ".JuceFirebaseInstanceIdService");
service->setAttribute ("android:name", "com.roli.juce.JuceFirebaseInstanceIdService");
intentFilter = service->createNewChildElement ("intent-filter");
intentFilter->createNewChildElement ("action")->setAttribute ("android:name", "com.google.firebase.INSTANCE_ID_EVENT");


+ 20
- 0
modules/juce_gui_basics/native/javaopt/app/com/roli/juce/JuceActivity.java View File

@@ -0,0 +1,20 @@
package com.roli.juce;

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

//==============================================================================
public class JuceActivity extends Activity
{
//==============================================================================
private native void appNewIntent (Intent intent);

@Override
protected void onNewIntent (Intent intent)
{
super.onNewIntent(intent);
setIntent(intent);

appNewIntent (intent);
}
}

+ 3
- 5
modules/juce_gui_extra/misc/juce_PushNotifications.h View File

@@ -700,11 +700,9 @@ private:
#if JUCE_ANDROID
friend bool juce_handleNotificationIntent (void*);
friend void juce_firebaseDeviceNotificationsTokenRefreshed (void*);
friend void juce_firebaseRemoteNotificationReceived (void*);
friend void juce_firebaseRemoteMessagesDeleted();
friend void juce_firebaseRemoteMessageSent (void*);
friend void juce_firebaseRemoteMessageSendError (void*, void*);
friend struct JuceFirebaseInstanceIdService;
friend struct JuceFirebaseMessagingService;
#endif
#if JUCE_PUSH_NOTIFICATIONS


+ 16
- 0
modules/juce_gui_extra/native/javaopt/app/com/roli/juce/JuceFirebaseInstanceIdService.java View File

@@ -0,0 +1,16 @@
package com.roli.juce;

import com.google.firebase.iid.*;

public final class JuceFirebaseInstanceIdService extends FirebaseInstanceIdService
{
private native void firebaseInstanceIdTokenRefreshed (String token);

@Override
public void onTokenRefresh()
{
String token = FirebaseInstanceId.getInstance().getToken();

firebaseInstanceIdTokenRefreshed (token);
}
}

+ 35
- 0
modules/juce_gui_extra/native/javaopt/app/com/roli/juce/JuceFirebaseMessagingService.java View File

@@ -0,0 +1,35 @@
package com.roli.juce;

import com.google.firebase.messaging.*;

public final class JuceFirebaseMessagingService extends FirebaseMessagingService
{
private native void firebaseRemoteMessageReceived (RemoteMessage message);
private native void firebaseRemoteMessagesDeleted();
private native void firebaseRemoteMessageSent (String messageId);
private native void firebaseRemoteMessageSendError (String messageId, String error);

@Override
public void onMessageReceived (RemoteMessage message)
{
firebaseRemoteMessageReceived (message);
}

@Override
public void onDeletedMessages()
{
firebaseRemoteMessagesDeleted();
}

@Override
public void onMessageSent (String messageId)
{
firebaseRemoteMessageSent (messageId);
}

@Override
public void onSendError (String messageId, Exception e)
{
firebaseRemoteMessageSendError (messageId, e.toString());
}
}

+ 98
- 43
modules/juce_gui_extra/native/juce_android_PushNotifications.cpp View File

@@ -203,8 +203,8 @@ DECLARE_JNI_CLASS_WITH_MIN_SDK (RemoteInputBuilder, "android/app/RemoteInput$Bui
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
STATICMETHOD (getInstance, "getInstance", "()Lcom/google/firebase/messaging/FirebaseMessaging;") \
METHOD (send, "send", "(Lcom/google/firebase/messaging/RemoteMessage;)V") \
METHOD (subscribeToTopic, "subscribeToTopic", "(Ljava/lang/String;)V") \
METHOD (unsubscribeFromTopic, "unsubscribeFromTopic", "(Ljava/lang/String;)V") \
METHOD (subscribeToTopic, "subscribeToTopic", "(Ljava/lang/String;)Lcom/google/android/gms/tasks/Task;") \
METHOD (unsubscribeFromTopic, "unsubscribeFromTopic", "(Ljava/lang/String;)Lcom/google/android/gms/tasks/Task;") \
DECLARE_JNI_CLASS (FirebaseMessaging, "com/google/firebase/messaging/FirebaseMessaging")
#undef JNI_CLASS_MEMBERS
@@ -349,7 +349,7 @@ struct PushNotifications::Pimpl
void notifyListenersAboutLocalNotification (const LocalRef<jobject>& intent)
{
auto* env = getEnv();
LocalRef<jobject> context (getAppContext());
LocalRef<jobject> context (getMainActivity());
auto bundle = LocalRef<jobject> (env->CallObjectMethod (intent, AndroidIntent.getExtras));
@@ -461,6 +461,7 @@ struct PushNotifications::Pimpl
#endif
}
//==========================================================================
void subscribeToTopic (const String& topic)
{
#if defined(JUCE_FIREBASE_MESSAGING_SERVICE_CLASSNAME)
@@ -469,7 +470,7 @@ struct PushNotifications::Pimpl
auto firebaseMessaging = LocalRef<jobject> (env->CallStaticObjectMethod (FirebaseMessaging,
FirebaseMessaging.getInstance));
env->CallVoidMethod (firebaseMessaging, FirebaseMessaging.subscribeToTopic, javaString (topic).get());
env->CallObjectMethod (firebaseMessaging, FirebaseMessaging.subscribeToTopic, javaString (topic).get());
#else
ignoreUnused (topic);
#endif
@@ -483,7 +484,7 @@ struct PushNotifications::Pimpl
auto firebaseMessaging = LocalRef<jobject> (env->CallStaticObjectMethod (FirebaseMessaging,
FirebaseMessaging.getInstance));
env->CallVoidMethod (firebaseMessaging, FirebaseMessaging.unsubscribeFromTopic, javaString (topic).get());
env->CallObjectMethod (firebaseMessaging, FirebaseMessaging.unsubscribeFromTopic, javaString (topic).get());
#else
ignoreUnused (topic);
#endif
@@ -545,7 +546,7 @@ struct PushNotifications::Pimpl
void notifyListenersAboutRemoteNotificationFromService (const LocalRef<jobject>& remoteNotification)
{
#if defined(JUCE_FIREBASE_MESSAGING_SERVICE_CLASSNAME)
GlobalRef rn (remoteNotification.get());
GlobalRef rn (remoteNotification);
MessageManager::callAsync ([this, rn]
{
@@ -570,7 +571,7 @@ struct PushNotifications::Pimpl
void notifyListenersAboutUpstreamMessageSent (const LocalRef<jstring>& messageId)
{
#if defined(JUCE_FIREBASE_MESSAGING_SERVICE_CLASSNAME)
GlobalRef mid (messageId);
GlobalRef mid (LocalRef<jobject>(messageId.get()));
MessageManager::callAsync ([this, mid]
{
@@ -586,7 +587,7 @@ struct PushNotifications::Pimpl
const LocalRef<jstring>& error)
{
#if defined(JUCE_FIREBASE_MESSAGING_SERVICE_CLASSNAME)
GlobalRef mid (messageId), e (error);
GlobalRef mid (LocalRef<jobject>(messageId.get())), e (LocalRef<jobject>(error.get()));
MessageManager::callAsync ([this, mid, e]
{
@@ -603,7 +604,7 @@ struct PushNotifications::Pimpl
static LocalRef<jobject> getNotificationManager()
{
auto* env = getEnv();
LocalRef<jobject> context (getAppContext());
LocalRef<jobject> context (getMainActivity());
return LocalRef<jobject> (env->CallObjectMethod (context.get(),
AndroidContext.getSystemService,
@@ -631,7 +632,7 @@ struct PushNotifications::Pimpl
static LocalRef<jobject> createNotificationBuilder (const PushNotifications::Notification& n)
{
auto* env = getEnv();
LocalRef<jobject> context (getAppContext());
LocalRef<jobject> context (getMainActivity());
jclass builderClass = env->FindClass ("android/app/Notification$Builder");
jassert (builderClass != 0);
@@ -663,7 +664,7 @@ struct PushNotifications::Pimpl
static void setupRequiredFields (const PushNotifications::Notification& n, LocalRef<jobject>& notificationBuilder)
{
auto* env = getEnv();
LocalRef<jobject> context (getAppContext());
LocalRef<jobject> context (getMainActivity());
auto activityClass = LocalRef<jobject> (env->CallObjectMethod (context.get(), JavaObject.getClass));
auto notifyIntent = LocalRef<jobject> (env->NewObject (AndroidIntent, AndroidIntent.constructorWithContextAndClass, context.get(), activityClass.get()));
@@ -902,7 +903,7 @@ struct PushNotifications::Pimpl
LocalRef<jobject>& notificationBuilder)
{
auto* env = getEnv();
LocalRef<jobject> context (getAppContext());
LocalRef<jobject> context (getMainActivity());
auto activityClass = LocalRef<jobject> (env->CallObjectMethod (context.get(), JavaObject.getClass));
auto deleteIntent = LocalRef<jobject> (env->NewObject (AndroidIntent, AndroidIntent.constructorWithContextAndClass, context.get(), activityClass.get()));
@@ -930,7 +931,7 @@ struct PushNotifications::Pimpl
return;
auto* env = getEnv();
LocalRef<jobject> context (getAppContext());
LocalRef<jobject> context (getMainActivity());
int actionIndex = 0;
@@ -1025,7 +1026,7 @@ struct PushNotifications::Pimpl
static LocalRef<jobject> juceUrlToAndroidUri (const URL& url)
{
auto* env = getEnv();
LocalRef<jobject> context (getAppContext());
LocalRef<jobject> context (getMainActivity());
auto packageNameString = LocalRef<jstring> ((jstring) (env->CallObjectMethod (context.get(), AndroidContext.getPackageName)));
@@ -1351,7 +1352,7 @@ struct PushNotifications::Pimpl
dataDynamicObject->setProperty (juceString (key.get()), juceString (value.get()));
}
var dataVar (dataDynamicObject);
var dataVar (dataDynamicObject.get());
DynamicObject::Ptr propertiesDynamicObject = new DynamicObject();
propertiesDynamicObject->setProperty ("collapseKey", juceString (collapseKey.get()));
@@ -1402,7 +1403,7 @@ struct PushNotifications::Pimpl
propertiesDynamicObject->setProperty ("link", link.get() != 0 ? juceString ((jstring) env->CallObjectMethod (link, AndroidUri.toString)) : String());
}
n.properties = var (propertiesDynamicObject);
n.properties = var (propertiesDynamicObject.get());
return n;
}
@@ -1492,7 +1493,7 @@ struct PushNotifications::Pimpl
static bool intentActionContainsAnyOf (jobject intent, const StringArray& strings, bool includePackageName)
{
auto* env = getEnv();
LocalRef<jobject> context (getAppContext());
LocalRef<jobject> context (getMainActivity());
String packageName = includePackageName ? juceString ((jstring) env->CallObjectMethod (context.get(),
AndroidContext.getPackageName))
@@ -1551,6 +1552,70 @@ struct PushNotifications::Pimpl
PushNotifications& owner;
};
#if defined(JUCE_FIREBASE_INSTANCE_ID_SERVICE_CLASSNAME)
//==============================================================================
struct JuceFirebaseInstanceIdService
{
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
CALLBACK (tokenRefreshed, "firebaseInstanceIdTokenRefreshed", "(Ljava/lang/String;)V")
DECLARE_JNI_CLASS (InstanceIdService, "com/roli/juce/JuceFirebaseInstanceIdService")
#undef JNI_CLASS_MEMBERS
static void JNICALL tokenRefreshed (void* token)
{
if (auto* instance = PushNotifications::getInstanceWithoutCreating())
instance->pimpl->notifyListenersTokenRefreshed (juceString (static_cast<jstring> (token)));
}
};
JuceFirebaseInstanceIdService::InstanceIdService_Class JuceFirebaseInstanceIdService::InstanceIdService;
#endif
#if defined(JUCE_FIREBASE_MESSAGING_SERVICE_CLASSNAME)
//==============================================================================
struct JuceFirebaseMessagingService
{
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
CALLBACK (remoteNotificationReceived, "firebaseRemoteMessageReceived", "(Lcom/google/firebase/messaging/RemoteMessage;)V") \
CALLBACK (remoteMessagesDeleted, "firebaseRemoteMessagesDeleted", "()V") \
CALLBACK (remoteMessageSent, "firebaseRemoteMessageSent", "(Ljava/lang/String;)V") \
CALLBACK (remoteMessageSendError, "firebaseRemoteMessageSendError", "(Ljava/lang/String;Ljava/lang/String;)V")
DECLARE_JNI_CLASS (MessagingService, "com/roli/juce/JuceFirebaseMessagingService")
#undef JNI_CLASS_MEMBERS
static void JNICALL remoteNotificationReceived (JNIEnv*, jobject /*messagingService*/, void* remoteMessage)
{
if (auto* instance = PushNotifications::getInstanceWithoutCreating())
instance->pimpl->notifyListenersAboutRemoteNotificationFromService (LocalRef<jobject> (static_cast<jobject> (remoteMessage)));
}
static void JNICALL remoteMessagesDeleted()
{
if (auto* instance = PushNotifications::getInstanceWithoutCreating())
instance->pimpl->notifyListenersAboutRemoteNotificationsDeleted();
}
static void JNICALL remoteMessageSent (JNIEnv*, jobject /*messagingService*/, void* messageId)
{
if (auto* instance = PushNotifications::getInstanceWithoutCreating())
instance->pimpl->notifyListenersAboutUpstreamMessageSent (LocalRef<jstring> (static_cast<jstring> (messageId)));
}
static void JNICALL remoteMessageSendError (JNIEnv*, jobject /*messagingService*/, void* messageId, void* error)
{
if (auto* instance = PushNotifications::getInstanceWithoutCreating())
instance->pimpl->notifyListenersAboutUpstreamMessageSendingError (LocalRef<jstring> (static_cast<jstring> (messageId)),
LocalRef<jstring> (static_cast<jstring> (error)));
}
};
JuceFirebaseMessagingService::MessagingService_Class JuceFirebaseMessagingService::MessagingService;
#endif
//==============================================================================
bool juce_handleNotificationIntent (void* intent)
{
auto* instance = PushNotifications::getInstanceWithoutCreating();
@@ -1582,35 +1647,25 @@ bool juce_handleNotificationIntent (void* intent)
return false;
}
void juce_firebaseDeviceNotificationsTokenRefreshed (void* token)
{
if (auto* instance = PushNotifications::getInstanceWithoutCreating())
instance->pimpl->notifyListenersTokenRefreshed (juceString (static_cast<jstring> (token)));
}
void juce_firebaseRemoteNotificationReceived (void* remoteMessage)
//==============================================================================
struct JuceActivityNewIntentListener
{
if (auto* instance = PushNotifications::getInstanceWithoutCreating())
instance->pimpl->notifyListenersAboutRemoteNotificationFromService (LocalRef<jobject> (static_cast<jobject> (remoteMessage)));
}
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
CALLBACK (appNewIntent, "appNewIntent", "(Landroid/content/Intent;)V")
void juce_firebaseRemoteMessagesDeleted()
{
if (auto* instance = PushNotifications::getInstanceWithoutCreating())
instance->pimpl->notifyListenersAboutRemoteNotificationsDeleted();
}
DECLARE_JNI_CLASS (JavaActivity, JUCE_PUSH_NOTIFICATIONS_ACTIVITY)
#undef JNI_CLASS_MEMBERS
void juce_firebaseRemoteMessageSent (void* messageId)
{
if (auto* instance = PushNotifications::getInstanceWithoutCreating())
instance->pimpl->notifyListenersAboutUpstreamMessageSent (LocalRef<jstring> (static_cast<jstring> (messageId)));
}
static void JNICALL appNewIntent (JNIEnv*, jobject /*activity*/, jobject intentData)
{
#if JUCE_PUSH_NOTIFICATIONS && JUCE_MODULE_AVAILABLE_juce_gui_extra
juce_handleNotificationIntent(static_cast<void*>(intentData));
#else
juce::ignoreUnused(intentData);
#endif
}
};
void juce_firebaseRemoteMessageSendError (void* messageId, void* error)
{
if (auto* instance = PushNotifications::getInstanceWithoutCreating())
instance->pimpl->notifyListenersAboutUpstreamMessageSendingError (LocalRef<jstring> (static_cast<jstring> (messageId)),
LocalRef<jstring> (static_cast<jstring> (error)));
}
JuceActivityNewIntentListener::JavaActivity_Class JuceActivityNewIntentListener::JavaActivity;
} // namespace juce

Loading…
Cancel
Save