My app's notification is working fine, receiving notifications on background and foreground, using firebase-native plugin .Now, my client needs the app open when the notification is received without any user iteration.
I've found was this, but has no correct answer for me.
On my debug, I've realize that the notification is received via broadcast by FirebaseInstanceIdReceiver. So, I've tried:
Modify the
plugins/cordova-plugin-firebase-lib/plugin.xml
This compile but nothing happens.
Modify the config.xml and use to replace config.xml of firebase-lib and merge with mine, calling the right intent.
This not compile and give me this error:
MY QUESTION IS: What is the best approach to archive this? Can someone guide me with a real example?
Thank you for your time!
If someone need this, the solution that work for me was use the "#ionic-native/background-mode" plugin.
The resolution for this problem it's pretty easy actually. No need for intent, just install the '#ionic-native/background-mode'.
For Ionic 3, install the plugin using this command:
ionic cordova plugin add cordova-plugin-background-mode
npm install --save #ionic-native/background-mode#4
File: app.module.ts:
import {BackgroundMode} from "#ionic-native/background-mode";
Add on providers:
providers: [
BackgroundMode,
...
],
File: app.component.ts:
Import the background-mode plugin:
import {BackgroundMode} from "#ionic-native/background-mode";
Add on constructor
constructor(
platform: Platform,
statusBar: StatusBar,
splashScreen: SplashScreen,
...
private backgroundMode: BackgroundMode) {
this.backgroundMode.enable();
this.backgroundMode.excludeFromTaskList();
this.backgroundMode.overrideBackButton();
// this.backgroundMode.setDefaults({silent: true});
this.backgroundMode.on('activate').subscribe(value => {
this.backgroundMode.disableWebViewOptimizations();
});
}
File: fcm.ts
Here is where all Firebase notification are. First, import the background-mode:
import {BackgroundMode} from "#ionic-native/background-mode";
Now, we just call these two functions on onNotificationOpen, which is the function that firebase call when notification arrives:
listenToNotifications() {
return this.firebaseNative.onNotificationOpen()
}
this.listenToNotifications().subscribe(
((msg: any) => {
// 'These two functions make the magic'
this.backgroundMode.unlock();
this.backgroundMode.moveToForeground();
if (!msg.tap)
this.events.publish(this.dataInfo.eventFcmNew, msg)
else
this.events.publish('push', 'NotificationsPage')
})
)
That's it!
Git Example
Related
My Main goal is to create an Electron App (Windows) that locally stores data in an SQLite Database. And because of type safety I choose to use the Prisma framework instead of other SQLite Frameworks.
I took this Electron Sample Project and now try to include Prisma. Depending on what I try different problems do arrise.
1. PrismaClient is unable to be run in the Browser
I executed npx prisma generate and then try to execute this function via a button:
import { PrismaClient } from '#prisma/client';
onSqlTestAction(): void {
const prisma = new PrismaClient();
const newTestObject = prisma.testTable.create(
{
data: {
value: "TestValue"
}
}
);
}
When executing this in Electron I get this:
core.js:6456 ERROR Error: PrismaClient is unable to be run in the browser.
In case this error is unexpected for you, please report it in https://github.com/prisma/prisma/issues
at new PrismaClient (index-browser.js:93)
at HomeComponent.onSqlTestAction (home.component.ts:19)
at HomeComponent_Template_button_click_7_listener (template.html:7)
at executeListenerWithErrorHandling (core.js:15281)
at wrapListenerIn_markDirtyAndPreventDefault (core.js:15319)
at HTMLButtonElement.<anonymous> (platform-browser.js:568)
at ZoneDelegate.invokeTask (zone.js:406)
at Object.onInvokeTask (core.js:28666)
at ZoneDelegate.invokeTask (zone.js:405)
at Zone.runTask (zone.js:178)
It somehow seems logical that Prisma cannot run in a browser. But I actually build a native app - with Electron that embeds a Browser. It seems to be a loophole.
2. BREAKING CHANGE: webpack < 5 used to include polyfills
So i found this Question: How to use Prisma with Electron
Seemed to be exactly what I looked for. But the error message is different (Debian binaries were not found).
The solution provided is to generate the prisma artifacts into the src folder instead of node_modules - and this leads to 19 polyfills errors. One for example:
./src/database/generated/index.js:20:11-26 - Error: Module not found: Error: Can't resolve 'path' in '[PATH_TO_MY_PROJECT]\src\database\generated'
BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need this module and configure a polyfill for it.
If you want to include a polyfill, you need to:
- add a fallback 'resolve.fallback: { "path": require.resolve("path-browserify") }'
- install 'path-browserify'
If you don't want to include a polyfill, you can use an empty module like this:
resolve.fallback: { "path": false }
And this repeats with 18 other modules. Since the error message to begin with was different I also doubt that this is the way to go.
I finally figured this out. What I needed to understand was, that all Electron apps consist of 2 parts: The Frontend Webapp (running in embedded Chromium) and a Node backend server. Those 2 parts are called IPC Main and IPC Renderer and they can communicate with each other. And since Prisma can only run on the main process which is the backend I had to send my SQL actions to the Electron backend and execute them there.
My minimal example
In the frontend (I use Angular)
// This refers to the node_modules folder of the Electron Backend, the folder where the main.ts file is located.
// I just use this import so that I can use the prisma generated classes for type safety.
import { TestTable } from '../../../app/node_modules/.prisma/client';
// Button action
onSqlTestAction(): void {
this.electronService.ipcRenderer.invoke("prisma-channel", 'Test input').then((value) => {
const testObject: TestTable = JSON.parse(value);
console.log(testObject);
});
The sample project I used already had this service to provide the IPC Renderer:
#Injectable({
providedIn: 'root'
})
export class ElectronService {
ipcRenderer: typeof ipcRenderer;
webFrame: typeof webFrame;
remote: typeof remote;
childProcess: typeof childProcess;
fs: typeof fs;
get isElectron(): boolean {
return !!(window && window.process && window.process.type);
}
constructor() {
// Conditional imports
if (this.isElectron) {
this.ipcRenderer = window.require('electron').ipcRenderer;
this.webFrame = window.require('electron').webFrame;
this.childProcess = window.require('child_process');
this.fs = window.require('fs');
// If you want to use a NodeJS 3rd party deps in Renderer process (like #electron/remote),
// it must be declared in dependencies of both package.json (in root and app folders)
// If you want to use remote object in renderer process, please set enableRemoteModule to true in main.ts
this.remote = window.require('#electron/remote');
}
}
And then in the Electron backend I first added "#prisma/client": "^3.0.1" to the package.json (for the Electron backend not the frontend). Then I added to the main.ts this function to handle the requests from the renderer:
// main.ts
ipcMain.handle("prisma-channel", async (event, args) => {
const prisma = new PrismaClient();
await prisma.testTable.create(
{
data: {
value: args
}
}
);
const readValue = await prisma.testTable.findMany();
return JSON.stringify(readValue);
})
This way of simply adding the IPC Main handler in the main.ts file of course is a big code smell but usefull as minimal example. I think I will move on with the achitecture concept presented in this article.
I want to use Cordova Firebase Dynamiclinks plugin : https://github.com/chemerisuk/cordova-plugin-firebase-dynamiclinks#installation in my Ionic 4 App.
There is an Ionic-native-plugin usage for this too : npm install #ionic-native/firebase-dynamic-links and usage :
import { FirebaseDynamicLinks } from '#ionic-native/firebase-dynamic-links/ngx';
constructor(private firebaseDynamicLinks: FirebaseDynamicLinks) { }
...
this.firebaseDynamicLinks.onDynamicLink()
.subscribe((res: any) => console.log(res), (error:any) => console.log(error));
Issue is : I want to use createDynamicLink(parameters) method available in Cordova Firebase Dynamiclinks plugin but Ionic-native-plugin says
Property 'createDynamicLink' does not exist on type 'FirebaseDynamicLinks'.
Therefore, I need to use Cordova Firebase Dynamiclinks directly and I tried doing using it like
import { cordova } from '#ionic-native/core';
...
cordova.plugins.firebase.dynamiclinks.createDynamicLink({
link: "https://google.com"
}).then(function(url) {
console.log("Dynamic link was created:", url);
});
But got error
Property 'plugins' does not exist on type '(pluginObj: any, methodName: string, config: CordovaOptions, args: IArguments | any[]) => any'.
Also tried removing import
cordova.plugins.firebase.dynamiclinks.createDynamicLink({
link: "https://google.com"
}).then(function(url) {
console.log("Dynamic link was created:", url);
});
And got this
Property 'firebase' does not exist on type 'CordovaPlugins'.
What is the correct usage of cordova plugins?
Update
Ionic-native-plugin now contains all the methods available in Cordova Firebase Dynamiclinks plugin.
I believe this is more fitting of a comment, but I don't quite have the reputation for it yet.
Currently, there is a PR open in the #ionic-team/ionic-native repo (here). This exposes the extra methods, but until then you can use the original repo here to get your desired effect. In order to install the repo you will have to follow the directions in the Developer guide here. Cheers!
I have developed an ionic 5 app that uses Firebase Dynamic Links and it works great but it took some effort. I watched videos to understand how Firebase Dynamic Links work but there is certainly much that is not shown.
To answer the original question you can always manually create a dynamic link which is what I do in our solution. We created a dynamic link that would help users onboard (register an account). Our dynamic link has custom onboardingId which originates from the backend process and the link is presented to the user via SMS text message.
This is in app.component.ts constructor
Here is some code that happens when the user clicks the dynamic link:
// Handle the logic here after opening the app (app is already installed) with the Dynamic link
this.firebaseDynamicLinks.onDynamicLink().subscribe((res: any) => {
console.log('app was opened with dynamic link');
console.log(res);
/* This only fires on subsequent calls and not on app start 20220208 STR
console.log(JSON.stringify(res)); //"{"deepLink":"https://localhost/onboard?onboardingId=8ed634b0-53b7-4a0f-b67e-12c06019982a","clickTimestamp":1643908387670,"minimumAppVersion":0}"
var dynamicLink = JSON.parse(JSON.stringify(res));
var deepLink = dynamicLink.deepLink;
console.log(deepLink);
if (deepLink.indexOf("onboard")>=0){
this.isOnboarding = true;
}
alert("deepLink ="+ deepLink);
*/
}, (error:any) => {
console.log(error)
});
I originally thought that Firebase handles all of the magic if the user doesn't have the app installed. I was wrong! You MUST also handle the code to pickup the dynamic link after the app is installed.
The code below will read the dynamic link from the clipboard and survives the app install process. Placed in app.component.ts ngOnInit().
this.platform.ready().then(() => {
this.firebaseDynamicLinks.getDynamicLink().then((data) => {
//added 20220208 STR try to help open the deep link if app is just installed
if (data != null) {
console.log(JSON.stringify(data));
//alert("initializeApp():"+JSON.stringify(data));
var dynamicLink = JSON.parse(JSON.stringify(data));
var deepLink = dynamicLink.deepLink;
console.log("initializeApp():"+deepLink);
if (deepLink != "") {
if (deepLink.indexOf("onboard")>=0){
this.isOnboarding = true;
this.deepLinkToOnboard(deepLink);
}
}
}
});}
So to handle dynamic links after you have the Firebase plugin installed, you must have two sections of code; one for handling if the app is already installed and another for handling the dynamic link if the app is not installed.
i want to build an application and use firebase for notification done a lot of search over google but did not find any good guide and solution , everything i tried ended into some errors . i tried ionic docs but they are all messy after the ionic v4 they shows everything about v4 i have my app almost finished up just this thing remains .
i will appreciate any help .
Any idea how to proceed? I'm most probably not configuring Firebase properly. I have placed google-services.json in the root directory, no problems there. but after that its all out of my understanding
AN ERROR OCCURRED WHILE RUNNING ionic cordova plugin add phonegap-plugin-push --variable SENDER_ID-150482406038 --SAVE EXIT CODE 1
Got this Working . Thanks everyone for help!
refrences used-
https://ionicframework.com/docs/v3/native/push/
https://github.com/phonegap/phonegap-plugin-push
works for
ionic 3.20.1
cordova 8.1.2
steps i followed
Removed my android platform using ionic cordova platform
removeandroid then i created it agin ionic cordova platform add
android. just to avoid any errors which my be there with my old
android version.
Got the google-services.json and placed it in the
rootDirectoryOfApp\platforms\android\app
then i run $ ionic cordova plugin add phonegap-plugin-push $ npm
install --save #ionic-native/push#4
Edit config.xml look for <platform name="android"> under that i
wrote <resource-file src="google-services.json"
target="app/google-services.json" />
Edit package.json look for "phonegap-plugin-push" and edit it
something like this
"phonegap-plugin-push": {
"ANDROID_SUPPORT_V13_VERSION": "27.+", // already there
"FCM_VERSION": "11.6.2", // already there
"SENDER_ID": "numeric key obtain from firebase console" // added
},
Open app.module.ts and import import { Push } from
'#ionic-native/push'; add Push under providers there ...
providers: [
StatusBar,
SplashScreen,
Push, ....
Then in a provider
i imported import { Push, PushObject, PushOptions } from '#ionic-native/push';
then in costructor i added private push: Push,
and in the class of that provider i wrote a function like below
pushSetup(){
// to check if we have permission
this.push.hasPermission()
.then((res: any) => {
if (res.isEnabled) {
console.log('We have permission to send push notifications');
} else {
console.log('We do not have permission to send push notifications');
}
});
// Create a channel (Android O and above). You'll need to provide the id, description and importance properties.
this.push.createChannel({
id: "testchannel1",
description: "My first test channel",
// The importance property goes from 1 = Lowest, 2 = Low, 3 = Normal, 4 = High and 5 = Highest.
importance: 3
}).then(() => console.log('Channel created'));
// Delete a channel (Android O and above)
this.push.deleteChannel('testchannel1').then(() => console.log('Channel deleted'));
// Return a list of currently configured channels
this.push.listChannels().then((channels) => console.log('List of channels', channels))
// to initialize push notifications
const options: PushOptions = {
android: {
senderID:"150482406038",
},
ios: {
alert: 'true',
badge: true,
sound: 'false'
},
};
const pushObject: PushObject = this.push.init(options);
pushObject.on('notification').subscribe((notification: any) => console.log('Received a notification', notification));
pushObject.on('registration').subscribe((registration: any) => console.log('Device registered', registration));
pushObject.on('error').subscribe(error => console.error('Error with Push plugin', error));
}
Now imported that provider where I want to use that , and called
that function from there . but call it only after
this.platform.ready().then(() => { or when a successful login.
I have shared this because i found it little difficult and got confusing guides over web
Please comment if you found it wrong or not working in your case.
I have been using this tutorial: https://medium.com/#felipepucinelli/how-to-add-push-notifications-in-your-cordova-application-using-firebase-69fac067e821 and Android push notifications worked out of the box. Good luck!
^ you might wanna try the cordova-plugin-firebase plugin as Chrillewoodz has mentioned
I am trying to get network status in ionic2, Ionic-native docs example is not working: My code is:
import { Component } from '#angular/core';
import { NavController } from 'ionic-angular';
import { Network } from '#ionic-native/network';
#Component( {
selector: 'page-network',
templateUrl: 'network.html'
})
export class NetworkPage {
Status: any = '';
ConnectionType:any = '';
constructor(private network: Network) {
let disconnectSubscription = this.network.onDisconnect().subscribe(() => {
this.Status = 'Disconnected';
console.log('network was disconnected ');
});
disconnectSubscription.unsubscribe();
let connectSubscription = this.network.onConnect().subscribe(() => {
console.log('network connected!');
this.Status = 'Connected';
setTimeout(() => {
if (this.network.type === 'wifi') {
console.log('we got a wifi connection, woohoo!');
}
}, 3000);
});
connectSubscription.unsubscribe();
}
}
i have using ionic2. error not come but still it not working for me. Need to check if network status enable or disable.
Make sure that you #ionic-native/core is installed, and in app.module.ts add Network to the providers in #NgModule decorator, finally you must inject or call the created service in somewhere usually in app.component.ts
Upadate
Remove the unsubscribe method on the listeners
disconnectSubscription.unsubscribe();
connectSubscription.unsubscribe();
I found out that you first subscribe to the network event then unsubscribe
Steps to make it work
Create ionic2 project
run the commands
ionic plugin add cordova-plugin-network-information
npm install --save #ionic-native/network
Add Network service in the providers array in the app.module.ts
In app.component.ts use this code.
Add the required platform lets choose Android
ionic platform add android
Then run the code
ionic run android
Finally try to enable/disable wifi and watch the console
I encounter the same issue this was how i solved it.
Make sure your
"#ionic-native/core": "~4.18.0",
and
"#ionic-native/network": "^4.18.0",
are the same version
by checking "#ionic-native/core" version on package.json in your project and installing
"#ionic-native/network" with the same version of "#ionic-native/core" e.g if "#ionic-native/core" version is "4.18.0" then install "#ionic-native/network" of 4.18.0 version
npm install #ionic-native/network#4.18.0
It should work like that.
After reviewing the new Mobile features with latest 1.0 version of Meteor, I'm not seeing where I would modify the Cordova code to add custom capabilities. For instance, I want to implement push notifications for my application on both iOS and Android. In both cases I would need to write some native code so that I could get devices registered and accept push notification messages.
Currently, I'm using MeteorRider to accomplish this and it works great. I have 3 separate projects for Meteor, Android and iOS. In the latter 2, I put the native code there necessary to accomplish this. One thing is for certain, you have to update the bootstrap classes in Cordova to allow registrations to work.
In Meteor 1.0, how would I go about accomplishing this with the out-of-the-box mobile feature?
Here's the objective-C code for accepting push notification registration responses that is required in Cordova's AppDelegate:
- (void) application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
NSLog( #"Device token is: %#", deviceToken);
// Convert to string that can be stored in DB
NSString *regId = [[deviceToken description] stringByReplacingOccurrencesOfString:#"<" withString:#""];
regId = [regId stringByReplacingOccurrencesOfString:#">" withString:#""];
regId = [regId stringByReplacingOccurrencesOfString: #" " withString: #""];
[[ApplePushNotificationService sharedInstance] application:application uploadDeviceToken:regId];
}
- (void)application:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(NSError*)error
{
NSLog(#"Failed to get token, error: %#", error);
}
TL;DR : The cordova project is in the .meteor/local/cordova-build subfolder.
The default AppDelegate.m gets created in the .meteor/local/cordova-build/platforms/ios/***YOUR_APP_NAME***/Classes subfolder.
If you add a top-level folder called cordova-build-override to your meteor project, the directory tree that it contains will be added to the .meteor/local/cordova-build folder just before the build and compilation step.
So, put your custom AppDelegate.m in a new folder called cordova-build-override/platforms/ios/***YOUR_APP_NAME***/Classes .
mkdir -p cordova-build-override/platforms/ios/foo/Classes
cp .meteor/local/cordova-build/platforms/ios/foo/Classes/AppDelegate.m cordova-build-override/platforms/ios/foo/Classes
The Meteor-Cordova integration page on the GitHub Meteor wiki is the best place (so far) to find the details of cordova development with meteor.
You put your cordova-specific code in plain javascript. It's best not to modify the native code if at all possible; instead, see if you can write your own cordova plugin and use it from your meteor app. The cordova PushPlugin plugin might do what you're looking for, but if not, you can use it as a reference.
This example below will create a new iOS app that uses a non-meteor cordova plugin, from scratch.
NOTE: This is a bare minimum example. Look at the meteor cordova camera plugin for a full example. The code below is based on that plugin.
# create a meteor app foo
meteor create foo
cd foo
# add the iOS cordova platform
meteor add-platform ios
# create a new meteor package, foo-camera.
# NOTE: You need to substitute your own meteor.com developer ID here
meteor create --package your_meteor_developer_id:foo-camera
Now, edit the packages/your_meteor_developer_id:foo-camera/package.js file to add the following:
// Add the camera cordova plugin at version 0.3.3
Cordova.depends({
'org.apache.cordova.camera': '0.3.3'
});
EDIT 1: This causes the plugin to be downloaded to your cordova plugins folder.
You can refer to a git tarball instead of a version number e.g. :
Cordova.depends({
'com.phonegap.plugins.facebookconnect': 'https://github.com/Wizcorp/phonegap-facebook-plugin/tarball/0e61babb65bc1716b957b6294c7fdef3ce6ace79'
});
source: meteor cordova wiki
While we're at it, limit our code to run only on the client, and export our FooCamera object so it can be used in the rest of our meteor javascript:
Package.onUse(function(api) {
api.versionsFrom('1.0');
api.export('FooCamera');
api.addFiles('your_meteor_developer_id:foo-camera.js','client');
});
Edit 2:
If your cordova plugin needs special configuration, you can define this in your meteor app's
mobile configuration file. It will get copied into
your app's config.xml .
E.g.
// ===== mobile-config.js ======
// Set PhoneGap/Cordova preferences
App.setPreference('SOME_SPECIFIC_PLUGIN_KEY','SOME_SPECIFIC_PLUGIN_VAL');
Your app's config.xml will then eventually result in the following:
<preference name="SOME_SPECIFIC_PLUGIN_KEY" value="SOME_SPECIFIC_PLUGIN_VAL"/>
Next, edit the JavaScript file in your package ( packages/your_meteor_developer_id:foo-camera/your_meteor_developer_id:foo-camera.js ) to expose the cordova functionality in a meteor-like manner. Use the official meteor mobile package examples as a reference.
(the code below is stolen shamelessly from the meteor github repo ) :
FooCamera = {};
FooCamera.getPicture = function (options, callback) {
// if options are not passed
if (! callback) {
callback = options;
options = {};
}
var success = function (data) {
callback(null, "data:image/jpeg;base64," + data);
};
var failure = function (error) {
callback(new Meteor.Error("cordovaError", error));
};
// call the cordova plugin here, and pass the result to our callback.
navigator.camera.getPicture(success, failure,
_.extend(options, {
quality: options.quality || 49,
targetWidth: options.width || 640,
targetHeight: options.height || 480,
destinationType: Camera.DestinationType.DATA_URL
})
);
};
Now, add your new (local) package to your meteor app.
meteor add your_meteor_developer_id:foo-camera
Edit your application's main HTML and JS to use your new meteor package.
In your foo.html , replace the hello template with this:
<template name="hello">
<button>Take a Photo</button>
{{#if photo}}
<div>
<img src={{photo}} />
</div>
{{/if}}
</template>
In your foo.js , replace the button click event handler with this:
Template.hello.helpers({
photo: function () {
return Session.get("photo");
}
});
Template.hello.events({
'click button': function () {
var cameraOptions = {
width: 800,
height: 600
};
FooCamera.getPicture(cameraOptions, function (error, data) {
Session.set("photo", data);
});
}
});
Now, plug your device in, make sure it's on the same network as your computer, and start both the meteor server and the ios app.
meteor run ios-device
# If you want to just use the emulator, use the following instead.
# but of course the camera won't work on the emulator.
#meteor run ios
XCode will open. You may need to set up your certificates and provisioning profiles before running your app (from XCode).
In another terminal, tail the logs:
tail -f .meteor/local/cordova-build/platforms/ios/cordova/console.log
Finally, publish your excellent meteor cordova plugin so that everyone else can use it. Edit package.js as per the meteor docs. Then:
cd packages/your_meteor_developer_id\:foo-camera
meteor publish