Add FCM device registration and Gitea bug reporter
This commit is contained in:
@@ -1,14 +1,15 @@
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
buildFeatures { buildConfig true }
|
||||
namespace "de.pinguholic.concerts"
|
||||
compileSdk rootProject.ext.compileSdkVersion
|
||||
defaultConfig {
|
||||
applicationId "de.pinguholic.concerts"
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
versionCode 2
|
||||
versionName "1.1.0"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
aaptOptions {
|
||||
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
|
||||
@@ -17,6 +18,10 @@ android {
|
||||
}
|
||||
}
|
||||
buildTypes {
|
||||
debug {
|
||||
versionNameSuffix '-debug'
|
||||
resValue 'string', 'app_name', 'MetalCircle (Test)'
|
||||
}
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
@@ -36,6 +41,8 @@ dependencies {
|
||||
implementation "androidx.coordinatorlayout:coordinatorlayout:$androidxCoordinatorLayoutVersion"
|
||||
implementation "androidx.core:core-splashscreen:$coreSplashScreenVersion"
|
||||
implementation project(':capacitor-android')
|
||||
// Also used by MetalCircleDevice to await token invalidation at account boundaries.
|
||||
implementation "com.google.firebase:firebase-messaging:$firebaseMessagingVersion"
|
||||
testImplementation "junit:junit:$junitVersion"
|
||||
androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
|
||||
androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
|
||||
@@ -44,11 +51,16 @@ dependencies {
|
||||
|
||||
apply from: 'capacitor.build.gradle'
|
||||
|
||||
try {
|
||||
def servicesJSON = file('google-services.json')
|
||||
if (servicesJSON.text) {
|
||||
apply plugin: 'com.google.gms.google-services'
|
||||
}
|
||||
} catch(Exception e) {
|
||||
logger.info("google-services.json not found, google-services plugin not applied. Push Notifications won't work")
|
||||
if (!file('google-services.json').exists()) {
|
||||
throw new GradleException('Add the local Firebase google-services.json to the Android app module before building.')
|
||||
}
|
||||
apply plugin: 'com.google.gms.google-services'
|
||||
|
||||
gradle.taskGraph.whenReady { graph ->
|
||||
if (graph.allTasks.any { it.name.toLowerCase().contains('release') }) {
|
||||
def capacitorConfig = new groovy.json.JsonSlurper().parse(file('src/main/assets/capacitor.config.json'))
|
||||
if (capacitorConfig.server?.cleartext || !capacitorConfig.server?.url?.startsWith('https://')) {
|
||||
throw new GradleException('Release builds require an HTTPS server configuration. Run cap sync without local test mode.')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!-- Only debug APKs can load the localhost server reached through adb reverse. -->
|
||||
<application android:usesCleartextTraffic="true" />
|
||||
</manifest>
|
||||
@@ -8,6 +8,9 @@
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme">
|
||||
<meta-data android:name="firebase_messaging_auto_init_enabled" android:value="false" />
|
||||
<meta-data android:name="firebase_analytics_collection_enabled" android:value="false" />
|
||||
<meta-data android:name="com.google.firebase.messaging.default_notification_icon" android:resource="@drawable/ic_notification" />
|
||||
|
||||
<activity
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode"
|
||||
@@ -38,4 +41,5 @@
|
||||
<!-- Permissions -->
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
</manifest>
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
package de.pinguholic.concerts;
|
||||
|
||||
import com.getcapacitor.BridgeActivity;
|
||||
import android.os.Bundle;
|
||||
|
||||
public class MainActivity extends BridgeActivity {}
|
||||
public class MainActivity extends BridgeActivity {
|
||||
@Override
|
||||
public void onCreate(Bundle state) {
|
||||
registerPlugin(MetalCircleDevicePlugin.class);
|
||||
super.onCreate(state);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
package de.pinguholic.concerts;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import com.getcapacitor.JSObject;
|
||||
import com.getcapacitor.Plugin;
|
||||
import com.getcapacitor.PluginCall;
|
||||
import com.getcapacitor.PluginMethod;
|
||||
import com.getcapacitor.annotation.CapacitorPlugin;
|
||||
import com.google.firebase.messaging.FirebaseMessaging;
|
||||
import java.util.UUID;
|
||||
|
||||
@CapacitorPlugin(name = "MetalCircleDevice")
|
||||
public class MetalCircleDevicePlugin extends Plugin {
|
||||
private SharedPreferences preferences() {
|
||||
return getContext().getSharedPreferences("metalcircle_push", Context.MODE_PRIVATE);
|
||||
}
|
||||
|
||||
@PluginMethod
|
||||
public void getInfo(PluginCall call) {
|
||||
SharedPreferences prefs = preferences();
|
||||
String id = prefs.getString("device_id", null);
|
||||
if (id == null) {
|
||||
id = UUID.randomUUID().toString();
|
||||
prefs.edit().putString("device_id", id).commit();
|
||||
}
|
||||
JSObject result = new JSObject();
|
||||
result.put("deviceId", id);
|
||||
result.put("appVersion", BuildConfig.VERSION_NAME);
|
||||
result.put("debug", BuildConfig.DEBUG);
|
||||
result.put("binding", prefs.getString("binding", ""));
|
||||
call.resolve(result);
|
||||
}
|
||||
|
||||
@PluginMethod
|
||||
public void prepareSession(PluginCall call) {
|
||||
String binding = call.getString("binding", "");
|
||||
if (!binding.isEmpty() && !binding.matches("[a-f0-9]{64}")) {
|
||||
call.reject("Invalid session binding");
|
||||
return;
|
||||
}
|
||||
if (binding.equals(preferences().getString("binding", ""))) {
|
||||
call.resolve();
|
||||
return;
|
||||
}
|
||||
FirebaseMessaging messaging = FirebaseMessaging.getInstance();
|
||||
messaging.setAutoInitEnabled(false);
|
||||
NotificationManager manager = (NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
manager.cancelAll();
|
||||
messaging.deleteToken().addOnCompleteListener(task -> {
|
||||
if (!task.isSuccessful()) {
|
||||
call.reject("Push reset unavailable; please retry");
|
||||
return;
|
||||
}
|
||||
preferences().edit().putString("binding", binding).commit();
|
||||
call.resolve();
|
||||
});
|
||||
}
|
||||
|
||||
@PluginMethod
|
||||
public void showDebugToken(PluginCall call) {
|
||||
// A release APK can never display or copy a registration token through this method.
|
||||
if (!BuildConfig.DEBUG || preferences().getString("binding", "").isEmpty()) {
|
||||
call.reject("Debug token unavailable");
|
||||
return;
|
||||
}
|
||||
boolean english = "en".equals(call.getString("language"));
|
||||
FirebaseMessaging.getInstance().getToken().addOnCompleteListener(task -> {
|
||||
if (!task.isSuccessful()) {
|
||||
call.reject("Push token unavailable");
|
||||
return;
|
||||
}
|
||||
getActivity().runOnUiThread(() -> {
|
||||
new AlertDialog.Builder(getActivity())
|
||||
.setTitle("FCM token — DEBUG ONLY")
|
||||
.setMessage(task.getResult())
|
||||
.setPositiveButton(english ? "Copy" : "Kopieren", (dialog, which) -> {
|
||||
ClipboardManager clipboard = (ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
clipboard.setPrimaryClip(ClipData.newPlainText("FCM debug token", task.getResult()));
|
||||
})
|
||||
.setNegativeButton(english ? "Close" : "Schließen", null)
|
||||
.show();
|
||||
call.resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp" android:height="24dp" android:viewportWidth="24" android:viewportHeight="24">
|
||||
<path android:fillColor="#FFFFFFFF" android:pathData="M12,2a10,10 0,1 0,0 20a10,10 0,1 0,0 -20M12,5a7,7 0,1 1,0 14a7,7 0,1 1,0 -14M7,8h2l3,4 3,-4h2v8h-2v-5l-3,4 -3,-4v5H7z" />
|
||||
</vector>
|
||||
@@ -2,6 +2,8 @@ ext {
|
||||
minSdkVersion = 22
|
||||
compileSdkVersion = 34
|
||||
targetSdkVersion = 34
|
||||
// Capacitor Push Notifications 6.x's supported default (minSdk 22).
|
||||
firebaseMessagingVersion = '23.3.1'
|
||||
androidxActivityVersion = '1.8.0'
|
||||
androidxAppCompatVersion = '1.6.1'
|
||||
androidxCoordinatorLayoutVersion = '1.2.0'
|
||||
@@ -13,4 +15,4 @@ ext {
|
||||
androidxJunitVersion = '1.1.5'
|
||||
androidxEspressoCoreVersion = '3.5.1'
|
||||
cordovaAndroidVersion = '10.1.1'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,22 @@
|
||||
import type { CapacitorConfig } from '@capacitor/cli';
|
||||
|
||||
const serverUrl = process.env.METALCIRCLE_SERVER_URL || 'https://konzerte.pinguholic.de/';
|
||||
const localTest = process.env.METALCIRCLE_LOCAL_TEST === '1';
|
||||
if (!serverUrl.startsWith('https://') && !(localTest && /^http:\/\/(127\.0\.0\.1|localhost):\d+\/?$/.test(serverUrl))) {
|
||||
throw new Error('MetalCircle requires HTTPS, or explicit localhost test mode.');
|
||||
}
|
||||
|
||||
const config: CapacitorConfig = {
|
||||
appId: 'de.pinguholic.concerts',
|
||||
appName: 'MetalCircle',
|
||||
webDir: 'www',
|
||||
loggingBehavior: 'none',
|
||||
plugins: {
|
||||
PushNotifications: { presentationOptions: ['sound', 'alert'] }
|
||||
},
|
||||
server: {
|
||||
url: 'https://konzerte.pinguholic.de/',
|
||||
cleartext: false
|
||||
url: serverUrl,
|
||||
cleartext: localTest
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Generated
+1
-1
@@ -10,7 +10,7 @@
|
||||
"dependencies": {
|
||||
"@capacitor/android": "6.2.1",
|
||||
"@capacitor/core": "6.2.1",
|
||||
"@capacitor/push-notifications": "^6.0.5"
|
||||
"@capacitor/push-notifications": "6.0.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@capacitor/cli": "6.2.1",
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"dependencies": {
|
||||
"@capacitor/android": "6.2.1",
|
||||
"@capacitor/core": "6.2.1",
|
||||
"@capacitor/push-notifications": "^6.0.5"
|
||||
"@capacitor/push-notifications": "6.0.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@capacitor/cli": "6.2.1",
|
||||
|
||||
Reference in New Issue
Block a user