Apply Deep linking in flutter app for android and ios - java

Apply Deep Linking in flutter app to open
a specific page in another app or same app
i want to know to how implement deep links in flutter
or open channel with android native and ios native ?
?

I think it would be the same as in a normal android app. Deeplinking is a configuration thing rather than code.
You need to write some things in your android manifest.
Have a look at the firebase manual for deep linking:
Firebase deeplinking manual

You can use firebase dynamic links for deep linking in a flutter. Refer this link for full implement steps and create and receive a link, https://medium.com/better-programming/deep-linking-in-flutter-with-firebase-dynamic-links-8a4b1981e1eb.
Here is a sample code for receiving a link inside the app and open a new screen.
class MainWidgetState extends State<MainWidget> {
#override
void initState() {
super.initState();
this.initDynamicLinks();
}
initDynamicLinks(BuildContext context) async {
await Future.delayed(Duration(seconds: 3));
var data = await FirebaseDynamicLinks.instance.getInitialLink();
var deepLink = data?.link;
final queryParams = deepLink.queryParameters;
if (queryParams.length > 0) {
var userName = queryParams['userId'];
openNewScreen(userName);
}
FirebaseDynamicLinks.instance.onLink(onSuccess: (dynamicLink)
async {
var deepLink = dynamicLink?.link;
final queryParams = deepLink.queryParameters;
if (queryParams.length > 0) {
var userName = queryParams['userId'];
openNewScreen(userName);
}
debugPrint('DynamicLinks onLink $deepLink');
}, onError: (e) async {
debugPrint('DynamicLinks onError $e');
});
}
openNewScreen(String userName){
Navigator.of(context).pushNamed("routeFormScreen", arguments: {"name": userName});
}
}

Related

Ionic Capacitor Admob plugin loadAd null object reference

I am developing an Ionic Capacitor app and i am using the capacitor community ad plugin, but i am getting the following error in Android Studio:
java.lang.NullPointerException: Attempt to invoke virtual method 'void com.google.android.gms.ads.AdView.loadAd(com.google.android.gms.ads.AdRequest)' on a null object reference
I am running the application on an android phone with the command ionic capacitor run android -l --external
This is how the error happens:
the app opens on the Welcome page
the app shows a banner ad
i click the login button
the app removes the banner ad
the app navigates to the login page
the app should show a banner ad, BUT the app crashes
Welcome page (login page has the same life cycle methods and calls):
ionViewWillLeave(): void {
this.removeAd();
}
ionViewWillEnter(): void {
this.showAd();
}
private async showAd(): Promise<void> {
await this.admobService.showBanner();
}
private async removeAd(): Promise<void> {
await this.admobService.removeBanner();
}
Admob service:
public async showBanner(): Promise<void> {
AdMob.addListener(BannerAdPluginEvents.FailedToLoad, (info) => {
//console.log(info);
});
const options: BannerAdOptions = {
adId: 'hidden',
adSize: BannerAdSize.BANNER,
position: BannerAdPosition.TOP_CENTER,
margin: 0,
isTesting: true,
};
AdMob.showBanner(options);
}
public async removeBanner(): Promise<void> {
await AdMob.removeBanner();
}
Admob service is provided in root, and maybe that could be the case? But i would not like to provide it in every page specifically
Probably, the banner destroys while it trying to show. You can try add a delay via setTimeout (a few seconds for check this idea) for this.showAd(); call:
ionViewWillEnter(): void {
setTimeout(() => { this.showAd(); }, 3000);
}

How do I authenticate with my Google Cloud Function when using my Firebase App with Google Sign In?

I am a newbie (6 months going or so) and creating an app on Android (Java) that utilizes FireBase Auth with Google Sign In. (with only a few days of NodeJS exposure now) In other words my end user signs in with the Google Account. That part (I think) works pretty well so far. I use the Firestore Database heavily for a lot of things in the app.
So now I've gotten to the point where I want to use (Callable) Cloud Functions with HTTP Triggers. (never having done any of this before) I'm trying to get a proof of concept working at this time. The actual function works and I can trigger it from my app.
It appears that I cannot figure out how to make the function "private" though; as in "adding proper Members" to the Cloud function who have the right to invoke the function.
I have tried a few different things by trial error, but first let me show what I have.
This is the Cloud Function and I'm passing in an arbitrary String as a test, works nicely: (as long as "allUsers" have the role/right to invoke the function; in other words when the function is public.
exports.createTest = functions.https.onCall((data, context) => {
const text = data.text;
const uid = context.auth.uid;
const name = context.auth.token.name || null;
const email = context.auth.token.email || null;
console.log('UID: ', uid);
console.log('Name: ', name);
console.log('Email: ', email);
console.log('Message: ', text);
});
The above function gets triggered in my Android/Java code like this: (I think this code came from Google Doc/Sample/Example
private FirebaseFunctions mFunctions;
...
private void testing() {
mFunctions = FirebaseFunctions.getInstance();
Log.e(LOG_TAG, "Testing executed!");
String testMessage = "Hello Hello Testing 123 Mic Check";
createTest(testMessage)
.addOnCompleteListener(new OnCompleteListener<String>() {
#Override
public void onComplete(#NonNull Task<String> task) {
if (!task.isSuccessful()) {
Exception e = task.getException();
if (e instanceof FirebaseFunctionsException) {
FirebaseFunctionsException ffe = (FirebaseFunctionsException) e;
FirebaseFunctionsException.Code code = ffe.getCode();
Object details = ffe.getDetails();
Log.e(LOG_TAG, "FFE: " + ffe.getMessage() );
Log.e(LOG_TAG, "Code: " + code);
Log.e(LOG_TAG, "Details:" + details);
}
// ...
}
// ...
}
});
}
private Task<String> createTest(String text) {
// Create the arguments to the callable function.
Map<String, Object> data = new HashMap<>();
data.put("text", text);
data.put("push", true);
return mFunctions
.getHttpsCallable("createTest") //this is the function name
.call(data)
.continueWith(new Continuation<HttpsCallableResult, String>() {
#Override
public String then(#NonNull Task<HttpsCallableResult> task) throws Exception {
// This continuation runs on either success or failure, but if the task
// has failed then getResult() will throw an Exception which will be
// propagated down.
String result = (String) task.getResult().getData();
if (result != null) {
Log.e(LOG_TAG, "Result: " + result);
}
return result;
}
});
}
Only when I have "allUsers" added with the role/right to "invoke Cloud Function" then I get this working. My understanding of HTTP Requests and such is pretty limited, which is not making things easier.
I tried using the "allAuthenticatedUsers" options, which I figured would do the trick, because I actually authenticate my Users in the app through Firebase/Google Sign In. This Cloud Function shall only be available to either a) authenticated users or b) users of a specific domain. (I have a domain, let's say #testorganization.com) Or if I can identify my particular app (api key?) then that would work, too.
The moment I add a member "allAuthenticatedUsers" with role to invoke the function (and remove "allUsers) nothing happens. I also tried adding the entire domain, but that wouldn't work. (duh) Also tried adding my service account (trial and error at this point) and didn't seem to work.
In my Node JS code I am actually receiving the UID of the authenticated user, so it appears that some kind of user authentication information is already being exchanged.
With that knowledge, I can (successfully tried this) get the UID and cross check that against my database and verify a user that way, but seems unnecessary and I should be able to make the permissions work. (lock the function down entirely) Plus this took a really long time just finish this cross check. Or is this pretty standard procedure to do?
Like this-->
const usersRef = admin.firestore().collection('users').doc(uid)
usersRef.get()
.then((docSnapshot) => {
if (docSnapshot.exists) {
usersRef.onSnapshot((doc) => {
console.log('User Type logged in: ', doc.data().userCategory)
console.log('User Title: ', doc.data().userTitle)
});
} else {
console.log('User does not exist')
}
});
Edit:
So while not having figured out how to shut down the function entirely, I did discover that instead of cross checking my users, I can simple check for auth like this:
if (context.auth){
//user is auth'd
} else {
//no auth
}
That's a little bit better, I guess. (but still doesn't technically prevent access to the function?!)
Thank you so much for any help. Much appreciated.
Edit2:
Here is a screensshot of the area in the cloud console (for cloud function roles/privileges) that I am referring to:
https://imgur.com/cBsjaaL
With a Callable Cloud Function, if you want to ensure that only authenticated users can trigger it's business logic, you actually don't need to configure any extra "cloud function roles/privileges" as shown at the bottom of your question.
By default, with a Callable Cloud Function you will get, when available, "Firebase Authentication and FCM tokens automatically included in requests" and it will "automatically deserializes the request body and validates auth tokens", as explained in the doc.
So you just have to follow the doc and use the context parameter. As you have mentioned in your question, you can check the user is authenticated by doing:
if (context.auth) {
//...
}
If you want to verify the user email, you would do:
exports.addMessage = functions.https.onCall((data, context) => {
const uid = context.auth.uid;
return admin.auth().getUser(uid)
.then(userRecord => {
const userEmail = userRecord.email;
//....
})
.catch(function(error) {
console.log('Error fetching user data:', error);
// Send back an error to the front end
// See https://firebase.google.com/docs/functions/callable#handle_errors
});
});
You will find more examples on how to "work with" users with the Admin SDK here in the doc.

User migration to a new app using old auth token - InstallReferrer custom parameter

I have two app on Google Play. The old and new one. And I would like to use old auth token to the new app to be easier for users.
On the old app, the user has a popup to install the new app on Google Play.
I would like to pass the auth token in parameter to Google Play.
After new app has been installed, I would like to save the token in the new one app.
I tried to use Play Install Referrer Library but it didn't work.
The other way was to use SharedPreferences but MODE_WORLD_READABLE has been deprecated.
Old APP :
try {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=com.<PACKAGENAME>&token=pokpok&refresh_token=lolol"));
startActivity(intent);
} catch (Exception e) {
e.printStackTrace();
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=com.<PACKAGENAME>?token=pokpok&refresh_token=lolol")));
}
New APP code :
private fun shouldGetTokenFromOldApp() {
mReferrerClient = InstallReferrerClient.newBuilder(this).build()
mReferrerClient.startConnection(object : InstallReferrerStateListener {
override fun onInstallReferrerSetupFinished(responseCode: Int) {
when (responseCode) {
InstallReferrerClient.InstallReferrerResponse.OK -> {
// Connection established
val response: ReferrerDetails = mReferrerClient.installReferrer
val url = "https://play.google.com/store?${response.installReferrer}"
Log.d("APP", "Token old app 1 : $url")
val uri: Uri = Uri.parse(url)
val token = uri.getQueryParameter("token")
val refreshToken = uri.getQueryParameter("refresh_token")
Log.d("APP", "Token old app 2 : $token - $refreshToken")
mReferrerClient.endConnection()
}
InstallReferrerClient.InstallReferrerResponse.FEATURE_NOT_SUPPORTED -> {
// API not available on the current Play Store app
}
InstallReferrerClient.InstallReferrerResponse.SERVICE_UNAVAILABLE -> {
// Connection could not be established
}
}
}
override fun onInstallReferrerServiceDisconnected() {
// Try to restart the connection on the next request to
// Google Play by calling the startConnection() method.
}
})
}
This sounds like a nice thing to do for users, but seems very dangerous. You are sending an Auth token - something which if someone has it could allow them to login as that user anywhere off through untrusted systems like world readable files or referral parameters in URLs.
If you really need to do this, I'd suggest using some form of inter-app RPC (IPC) to communicate the token after the app is installed. One option would be a binder to a service that supplies the auth.

AWS Android Chat App

I am trying to make an android chat application. I am thinking about making it with aws. But the problem is that I am unable to find any good tutorial for doing this and I have no idea how to do it.
So could anyone please suggest some tutorial for sending push notification or on how to make a chat application?
Firebase is well suited to this due to its "realtime database" feature. Here's a few tutorials I found by Googling
https://code.tutsplus.com/tutorials/how-to-create-an-android-chat-app-using-firebase--cms-27397
http://myapptemplates.com/simple-android-chat-app-tutorial-firebase-integration/
https://codelabs.developers.google.com/codelabs/firebase-android/#0
Check Socket.IO for android. ( https://github.com/socketio/socket.io-client-java )
Its really easy to write a chat application. But you need a server side.
Easy to write a simple server for this chat app.
Server reveice the all message from clients and broadcast the message, to all.
Gradle:
compile 'com.github.nkzawa:socket.io-client:0.5.1'
Android manifest:
<uses-permission android:name="android.permission.INTERNET" />
Java
public static Socket mSocket;
try {
mSocket = IO.socket("http://192.168.1.104:4444");
mSocket.connect();
} catch (URISyntaxException e) {
e.printStackTrace();
}
Send messsage to server:
MainActivity.mSocket.emit("message","Text here...");
Create a listener for another message:
MainActivity.mSocket.on("newMessage", onMessageArrive); // Oncreate
private Emitter.Listener onMessageArrive = new Emitter.Listener() {
#Override
public void call(final Object... args) {
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
String data = (String)args[0];
// Here is all message. add it to list :) Or Push notif
}
});
}
};
// Server side:
var http = require('http');
var express = require('express'),
app = module.exports.app = express();
var io = require('socket.io').listen(app.listen(4444));
io.on('connection', function (socket) {
socket.on("message",function(msg){
io.sockets.emit('newMessage', msg);
});
});
Run:
npm install express
npm install socket.io
node filename.js
Just dont forget to check you IP! :)
Done! You have a Real Time Chat!!

Firebase persisted write failing after being offline

I have an Android application that uses Firebase as backend. Now that Firebase has support for local persistence I decided to get rid of my own local storage solution and use the built-in instead.
Everything is working, except for one thing. Making changes while being offline, closing the app, connect, and start the app.
The code that I use to update my data on the server is something like this:
public void saveDataToServer(String id, Boolean isHandled) {
Firebase firebase = new Firebase("https://example.firebaseio.com/item_data/items/1234/data").child(id);
if(firebase == null)
return;
firebase.authWithCustomToken(mToken, mAuthResultHandler);
Map<String, Object> children = new HashMap<>();
children.put("updated_at", FireBaseHelper.getFormattedTimestamp());
children.put("is_handled", isHandled);
firebase.updateChildren(children);
}
mMainFirebaseInstance is some Firebase object that is on the root level of where this data is saved. And this all runs in a Service that is connected to my Activities/Fragments
Sidenote:
I get the authentication token mToken from some REST API that someone else made for me to use.
When I am connected, have the app connected and make changes: everything works
When I am not connected, open the app, make changes, close the app, open the app and connect: everything works
When I am not connected, open the app, make changes, close the app, connect and open the app:
The following error is logged:
06-22 17:51:52.343 28073-28395/? W/RepoOperation﹕ Persisted write at /item_data/items/7454/data/7454141033945571998119 failed: FirebaseError: Invalid token in path
I've searched in Firebase's documentation and can't figure out where the problem is. I would say that this has something to do with the authentication, but I don't know anymore where to look.
So my question is: What is the problem here? What am I doing wrong?
EDIT:
The FireBaseHelper looks like this:
class FireBaseHelper {
public static Firebase getItemsBase(String itemId) {
Firebase fb = new Firebase(Constants.FIREBASE_URL + "item_data/items/" + itemId + "/data");
return fb;
}
public static String getFormattedTimestamp() {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US);
return simpleDateFormat.format(Calendar.getInstance().getTime());
}
}
It can create the main Firebase instance and return a timestamp in a specific format. Constants.FIREBASE_URL is just https://example.firebaseio.com/
EDIT2:
mMainFirebaseInstance = FireBaseHelper.getItemsBase("1234");
which would be replaceable by
mMainFirebaseInstance = new Firebase("https://example.firebaseio.com/item_data/items/1234/data");
A possible timestamp is:
2015-06-22 23:12:24
The id that is used in the saveDataToServer is retrieved from a snapshot that is given to me in a ValueEventListener. For example:
ValueEventListener valueEventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
HashMap data = dataSnapshot.getValue(HashMap.class);
Set keySet = data.keySet();
String id = keySet.get(0);
}
...
}
EDIT3:
Android: 5.0
Firebase: 2.3.0+
Java: 7
This turned out to be a bug in the Firebase Android SDK. It has been fixed in version 2.3.1 that was just released. See https://www.firebase.com/docs/android/changelog.html
I can reproduce the behavior you're seeing with this Activity.onCreate:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Firebase.setAndroidContext(this);
Firebase.getDefaultConfig().setPersistenceEnabled(true);
Firebase.getDefaultConfig().setLogLevel(Logger.Level.DEBUG);
Firebase ref = new Firebase("https://stackoverflow.firebaseio.com/30987733");
Map<String, Object> children = new HashMap<>();
children.put("updated_at", new Date().toString());
children.put("is_handled", true);
ref.updateChildren(children);
}
The steps to reproduce that go with the above code:
Go into airplane mode
Start the app (so that it calls updateChildren
Kill the app
Go online
Start the app
In my tests, the second update does get written to Firebase. But there is a warning written in the Android logs:
W/RepoOperation﹕ Persisted write at /30987733 failed: FirebaseError: Invalid token in path

Categories