Я перепробовал все прочитанное мной из сообщений Firebase и даже видео с YouTube, шаги, кажется, работают для иллюстратора, но не работают для меня. Вот мой файл манифеста:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package='com.app.name'>
<!-- io.flutter.app.FlutterApplication is an android.app.Application that
calls FlutterMain.startInitialization(this); in its onCreate method.
In most cases you can leave this as-is, but you if you want to provide
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. -->
<application
android:name="io.flutter.app.FlutterApplication"
android:label="iNotify"
android:icon="@mipmap/launcher_icon">
<activity
android:name=".MainActivity"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- This keeps the window background of the activity showing
until Flutter renders its first frame. It can be removed if
there is no splash screen (such as the default splash screen
defined in @style/LaunchTheme). -->
<meta-data
android:name="io.flutter.app.android.SplashScreenUntilFirstFrame"
android:value="true" />
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
<action android:name="FLUTTER_NOTIFICATION_CLICK" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<service
android:name=".java.MyFirebaseMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
</application>
</manifest>
Вот мой android/build.gradle
...
buildscript {
ext.kotlin_version = '1.3.50'
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.3'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'com.google.gms:google-services:4.2.0'
}
}
allprojects {
repositories {
google()
jcenter()
}
}
rootProject.buildDir = '../build'
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
project.evaluationDependsOn(':app')
}
task clean(type: Delete) {
delete rootProject.buildDir
}
и мой app/build.gradle
..
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader('UTF-8') { reader ->
localProperties.load(reader)
}
}
def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
flutterVersionCode = '1'
}
def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
flutterVersionName = '1.0'
}
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties')
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}
android {
compileSdkVersion 29
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
lintOptions {
disable 'InvalidPackage'
}
defaultConfig {
applicationId "com.ClioTech.iNotify"
minSdkVersion 16
targetSdkVersion 29
versionCode 1
versionName 'v1.0'
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
multiDexEnabled true
}
signingConfigs {
release {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
storePassword keystoreProperties['storePassword']
}
}
buildTypes {
release {
signingConfig signingConfigs.release
}
}
}
flutter {
source '../..'
}
dependencies {
implementation 'com.google.firebase:firebase-analytics:17.2.2'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'com.google.firebase:firebase-messaging:20.1.0'
implementation 'com.google.firebase:firebase-functions:16.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0'
}
apply plugin: 'com.google.gms.google-services'
Итак, я используя облачные функции для отправки уведомлений ... вот оно ...
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
import * as serviceAccount from './admin.json';
admin.initializeApp({
credential: admin.credential.cert(serviceAccount as any),
databaseURL: "https://xxxxxx.com"
});
const db = admin.firestore();
// list of tokens
const tokens: string[] = [];
// New document(error) added!
export const onCreate = functions.firestore.document('Messages/{MessageId}').onCreate((snapshot, context) => {
const newStation = snapshot.get('station');
const newError = snapshot.get('error');
const senderId = snapshot.get('from');
const data: { [key: string]: any } = {};
const docdata = db.doc(`${senderId}/${newStation}`).get();
docdata.then((Docsnapshot) => {
const numberOfErrorsGotten = Docsnapshot.get(`${newError}ErrorNumber`);
if (numberOfErrorsGotten === undefined) {
data[`${newError}ErrorNumber`] = 1;
db.doc(`${senderId}/${newStation}`).set(data, { merge: true }).catch((e) => { console.log(e); });
} else {
data[`${newError}ErrorNumber`] = numberOfErrorsGotten + 1;
db.doc(`${senderId}/${newStation}`).update(data).catch((e) => { console.log(e); });
}
}).catch((e) => { console.log(e); });
db.collection('Tokens').get().then((snapshots) => {
if (snapshots.empty) {
console.log('No Devices Connected.');
return;
} else {
for (const sweetToken of snapshots.docs) {
const actualToken = sweetToken.get('devtoken');
if (actualToken !== null) {
tokens.push(sweetToken.get('devtoken'));
} else {
db.doc(`Tokens/${actualToken}`).delete().catch((e) => { console.log(e); });
}
}
const payload = {
notification: {
title: senderId,
body: `${senderId} reported a(n) ${newError} error for ${newStation}.`,
sound: 'default',
},
};
return admin.messaging().sendToDevice(tokens, payload).then(() => { console.log('Sent to all devices') }).catch((e) => { console.log(e); });
}
}
).catch((e) => { console.log(e); });
return 0;
});
// Document(error) deleted
export const onDelete = functions.firestore.document('Messages/{MessageId}').onDelete((snapshot, context) => {
const senderId: string = snapshot.get('from');
const delStation: string = snapshot.get('station');
const delError: string = snapshot.get('error');
const path: string = senderId + '/' + delStation;
const error: string = delError + 'Error';
const desc: string = delError + 'Desc';
const numberData: { [key: string]: any } = {};
const data: { [key: string]: any } = {};
// reduce number
const docdata = db.doc(`${senderId}/${delStation}`).get();
docdata.then((sweetData) => {
const numberOfErrorsGotten = sweetData.get(`${delError}ErrorNumber`);
if (numberOfErrorsGotten === 1) {
numberData[`${delError}ErrorNumber`] = 0;
data[error] = false;
data[desc] = '';
db.doc(`${senderId}/${delStation}`).update(numberData).then((value) => { console.log('Updated number to zero') }).catch((e) => { console.log(e); });
db.doc(path).update(data).catch((e) => {
console.log(e);
})
} else {
numberData[`${delError}ErrorNumber`] -= 1;
db.doc(`${senderId}/${delStation}`).update(numberData).then((value) => { console.log('number reduced by 1') }).catch((e) => { console.log(e); });
}
}).catch((e) => { console.log(e); });
return 0;
});
// New token added!
export const newDevices = functions.firestore.document('Tokens/{Token}').onCreate((snapshot) => {
const newToken = snapshot.get('devtoken');
let payload = {
notification: {
title: 'iBot',
body: 'Welcome to the network.Visit /*www.appwebsite.com*/ our tutorials and FAQs for the best user experience.',
sound: 'default',
},
};
admin.messaging().sendToDevice(newToken, payload).then((later) => {
console.log('New member invited!');
}).catch((e) => { console.log('Invite error!'); });
console.log('New device connected to the network');
return 0;
});
// Notifications from admin
export const adminAddress = functions.firestore.document('AdminMessages/{AdminMessages}').onCreate((snapshot) => {
const adminMess = snapshot.get('message');
const from = snapshot.get('from');
var payload = {};
db.collection('Tokens').get().then((snapshots) => {
if (snapshots.empty) {
console.log('No Devices Connected.');
return;
} else {
for (const sweetToken of snapshots.docs) {
const actualToken = sweetToken.get('devtoken');
if (actualToken !== null) {
tokens.push(sweetToken.get('devtoken'));
} else {
db.doc(`Tokens/${actualToken}`).delete().catch((e) => { console.log(e); });
}
}
}
});
if (from === 'iBot') {
payload = {
notification: {
title: 'iBot',
body: `${adminMess}`,
},
};
console.log('New message by admin');
} else {
payload = {
notification: {
title: 'Administrator',
body: `${adminMess}`,
},
};
console.log('New message by iBot');
}
admin.messaging().sendToDevice(tokens, payload).then((latereven) => {
console.log('Admin message sent to devices!');
}).catch((e) => { console.log('Admin notification error!'); });
return 0;
});
Так что после создания нового элемента я получаю "отправить на устройства" и "отправить приглашение" в журнале консоли, как это ..
![Console logs](https://i.stack.imgur.com/zfMD2.jpg)
, но ни одно из устройств не получает уведомления ни в режиме отладки, ни в выпуске, ни на переднем плане, ни на заднем плане ..