A while back, I had a crash course on Advanced Android, where the instructor taught about Firebase. Although, I don't remember the details, he said we could control our apps' behavior from Firebase console (e.g. by calling a Cloud function?). For example, then I can get a trigger in my app and in response, I can decide whether to serve certain functions and features to the user or not (like remove an onClickListener from a button) based on e.g. they have paid the project price or subscription fee.
Is it possible to do using Firebase?
After some research and experiment I was able to implement this functionality into my app.
First you need to add Firebase Messaging to your project. Then, create a subclass of FirebaseMessagingService. Inside the class, implement onMessageReceived, where you can access messages received from server:
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private static final String TAG = MyFirebaseMessagingService.class.getSimpleName();
#Override
public void onNewToken(String s) {
super.onNewToken(s);
Log.d(TAG, "onNewToken: " + s);
}
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
Log.d(TAG, "onMessageReceived: " + remoteMessage.getData());
Log.d(TAG, "onMessageReceived: activation: "+ remoteMessage.getData().get(Constants.ACTIVATION_KEY));
boolean activation = Boolean.valueOf(remoteMessage.getData().get(Constants.ACTIVATION_KEY));
//Save in preferences
SharedPreferences prefs = getApplication().getSharedPreferences(Constants.PREFERENCE_FILE, MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean(Constants.ACTIVATION_KEY, activation);
editor.apply();
}
}
Make sure you add this service in your Manifest file:
<service android:name="me.mehdi.utils.MyFirebaseMessagingService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT"/>
</intent-filter>
</service>
In your Firebase Console select Cloud Messaging from the left and hit "New message". While composing a new message, you'll notice a section "Advanced options" in addition to message text and message label. Under Advanced options, you can enter key-value pairs and send to the device you select from the dropdown menu and finally hit Send message. In your onMessageReceived method, you can read the key-value pair and update your app's shared preferences to activate or deactivate certain features.
Related
I have a question. Can we add a invite button to the mobile app in android studio which on clicking gives referral link of the website instead of the application itself? Can we use firebase dynamic link for this or is it only to refer app itself?
I have added the code for dynamic link but its only to refer mobile app and not the website. I'd like to know if we can refer website as well.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_refer);
invite = findViewById(R.id.inviteBtn);
// calling the action bar
ActionBar actionBar = getSupportActionBar();
// showing the back button in action bar
actionBar.setDisplayHomeAsUpEnabled(true);
invite.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
inviteLink();
}
});
}
public void inviteLink(){
Log.e("main", "invite link");
DynamicLink dynamicLink = FirebaseDynamicLinks.getInstance().createDynamicLink()
.setLink(Uri.parse("https://www.versatileva.com.au/"))
.setDomainUriPrefix("versatileva.page.link")
.setAndroidParameters(new DynamicLink.AndroidParameters.Builder().build())
.setIosParameters(new DynamicLink.IosParameters.Builder("com.android.versatilevaproject").build())
.buildDynamicLink();
Uri dynamicLinkUri = dynamicLink.getUri();
Log.e("main", " Long refer "+ dynamicLink.getUri());
//versatileva.page.link?apn=com.android.versatilevaproject&ibi=com.android.versatilevaproject&link=https%3A%2F%2Fwww.versatileva.com.au%2F
}
}
Firebase provide this guide on rewarding user referrals using Dynamic Links. You can use Dynamic Links along with Realtime Database and Cloud Functions for Firebase to encourage your users to invite their friends by offering in-app rewards for successful referrals to both the referrer and the recipient.
Having android sdk which intercept the push notification, and has been using notification trampoline to further open the end activity. In the case of deeplink the app who uses this sdk will open the configured deeplink handler activity.
Snippet for the trampoline:
public class NotificationTrampolineReceiver extends BroadcastReceiver {
#Override
public void onReceive(final Context context, final Intent intent) {
final PendingResult asyncResult = goAsync();
ExecutorService executor = Executors.newSingleThreadExecutor();
asycTask(executor, new Runnable() {
#Override
public void run() {
String urlStr = getStringExtra(intent, PUSH_URL);
if (urlStr != null) {
var intent2: Intent = Intent(Intent.ACTION_VIEW, Uri.parse(urlStr));
if (intent2 != null) {
intent2.addFlags(FLAG_ACTIVITY_NEW_TASK);
intent2.addFlags(FLAG_ACTIVITY_BROUGHT_TO_FRONT);
context.startActivity(intent2);
logAnalytics(intent, Message.MessageAction.OPEN);
}
}
asyncResult.finish();
}
});
}
void asycTask(ExecutorService executor, final Runnable task) {
try {
executor.execute(task);
} catch (Throwable ex) {}
}
}
The notification trampolines is not working in Android 12 anymore.
The notification trampolines is needed in the sdk to intercept the click and do something like to log analytics event; closing the notification drawer when clicking at the Action button on the notification, etc. And this sdk does not know what activities the app may configure to handle the deeplinks.
Using a dummy activity to replace the trampoline would work, but not feel right, i.e. open the activity and inside to open another one then finish this one.
When android 12 puts restriction on the notification tramoline, does it suggest a replacement for the use case like the one here? Haven't find one.
What is the suggested new solution for intercepting the push notification tap first and then open the activity?
You are better off launching an Activity directly from the Notification. The Activity could then do the analytics and figure out what Activity needs to be launched and then delegate to that. As an alternative, the launched Activity could send the broadcast Intent to your BroadcastReceiver which could do the work.
NOTE: If you launch an Activity directly from a Notification, that is not a trampoline. The trampoline occurs when you launch a Service or a BroadcastReceiver directly from the Notification and that component then launches an Activity. The idea is that the user needs to be in control of what pops onto his screen. If he taps a notification, he expects that something will appear on his screen, if your Service launches an Activity, that can happen at any time and could possibly interrupt him.
This seems to be a simple task, but I`m failing to do it. Saw a bunch of tutorials and stuff. Maybe someone can help me.
I'm starting from a Xamarin Forms App, that will have a task specific for Android (Targeting Android 8.0 - Oreo).
So to test I've made as follow (XF 3.2.0.839982). Told this mainly because it don't have a OnResume, OnPause, On....methods...(or I don't know about them).
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity, Application.IActivityLifecycleCallbacks
{
SMSBroadcastReceiver myreceiver;
IntentFilter intentFilter;
protected override async void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
var buttonbtnsendmessage = (Button)FindViewById(Resource.Id.sendBroadcast);
myreceiver = new SMSBroadcastReceiver();
intentFilter = new IntentFilter(SMSBroadcastReceiver.IntentAction);
intentFilter.Priority = 1000;
RegisterReceiver(myreceiver, intentFilter);
}
}
public class SMSBroadcastReceiver : BroadcastReceiver
{
public static string IntentAction = "android.provider.Telephony.SMS_RECEIVED";
public override void OnReceive(Context context, Intent i)
{
if (i.Action != IntentAction)
{
return;
}
Toast.MakeText(context, "Received broadcast in MyBroadcastReceiver, " +
" value received: " + i.GetStringExtra("key"),
ToastLength.Long).Show();
}
}
and Manifest
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="26" />
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.BROADCAST_SMS" />
But it do not fall in my receiver when I get a SMS.
Just to check if it would work at all, I changed the IntentAction to "MY_TEST", and sent the broadcast from another app, and it was able to Toast.
Any Ideas?
Xamarin Forms - SMS BroadcastReceiver in Android failing to work
You are missing a lot is in your code.
Requesting Runtime Permissions in Android Marshmallow +
Beginning in Android 6.0 (API level 23), users grant permissions to apps while the app is running, not when they install the app. You should request permissions at runtime.
System permissions are divided into two categories, normal and dangerous:
Normal permissions do not directly risk the user's privacy. If your app lists a normal permission in its manifest, the system grants the permission automatically.
Dangerous permissions can give the app access to the user's confidential data. If you list a dangerous permission, the user has to explicitly give approval to your app during the runtime of the app.
READ_SMS is categorized as Dangerous permissions, so you should check this permissions manually for API level 23 and above.
Adorn BroadcastReceiver with the BroadcastReceiverAttribute
For more detail information, please refer to the official document: Broadcast Receivers in Xamarin.Android
Here is an example:
[BroadcastReceiver(Enabled = true)]
[IntentFilter(new[] { "android.provider.Telephony.SMS_RECEIVED" })]
class SMSBroadcastReceiver: BroadcastReceiver
{
public static string IntentAction = "android.provider.Telephony.SMS_RECEIVED";
public override void OnReceive(Context context, Intent i)
{
if (i.Action != IntentAction)
{
return;
}
Toast.MakeText(context, "Received broadcast in MyBroadcastReceiver, " +
" value received: " + i.GetStringExtra("key"),
ToastLength.Long).Show();
}
}
Now I am using Gluon plugin and it is very helpful to start working with JavaFXPorts. I have my application ready and I can use it on computers and phones. I tested on phone with system android. Application is working good but only with my server.
I take care of the different resolutions and I think that it is good for now.
I want to have Turn-based Multiplayer Application but I have still big problem with using Google Play Service. Tutorial which show how to use this services for turn-based multiplayer application is written in pure android and use Activity. My question is maybe very simple but If I have my application view from "fxml" how to use it as an tutorial Activity?
I want to do auto-matching for my application and next I want override method takeTurn() to suit it to my application.
For example, how can I change thing like that (code below) to application in JavaFX?
I must use google services from my JavaFX(src/main/java folder) class in addition AndroidPlatformProvider.java and all methods must be in src/android/java folder. I know that I must use PlatformService and PlatformProvider. I did it as in the examples: HelloPlatform and SMSTracker .
I use methods from my interface PlatformProvider but application still crashes. :(
I only use Provider from my code of JavaFX and I don't have android Activity. I don't know how to use these method without Activity or View:
- public void onActivityResult(int request, int response, Intent data)
- public void playTurn(View view)
Can I call from google service methods to methods from my controller for view (fxml).
I don't know how these methods should working with JavaFX.
public class TbmpGameActivity extends Activity {
...
#Override
public void onActivityResult(int request, int response, Intent data) {
super.onActivityResult(request, response, data);
...
if (request == RC_SELECT_PLAYERS) {
if (response != Activity.RESULT_OK) {
// user canceled
return;
}
// Get the invitee list.
final ArrayList<String> invitees =
data.getStringArrayListExtra(Games.EXTRA_PLAYER_IDS);
// Get auto-match criteria.
Bundle autoMatchCriteria = null;
int minAutoMatchPlayers = data.getIntExtra(
Multiplayer.EXTRA_MIN_AUTOMATCH_PLAYERS, 0);
int maxAutoMatchPlayers = data.getIntExtra(
Multiplayer.EXTRA_MAX_AUTOMATCH_PLAYERS, 0);
if (minAutoMatchPlayers > 0) {
autoMatchCriteria = RoomConfig.createAutoMatchCriteria(
minAutoMatchPlayers, maxAutoMatchPlayers, 0);
} else {
autoMatchCriteria = null;
}
TurnBasedMatchConfig tbmc = TurnBasedMatchConfig.builder()
.addInvitedPlayers(invitees)
.setAutoMatchCriteria(autoMatchCriteria)
.build();
// Create and start the match.
Games.TurnBasedMultiplayer
.createMatch(mGoogleApiClient, tbmc)
.setResultCallback(new MatchInitiatedCallback());
}
}
}
or something like that:
// Call this method when a player has completed his turn and wants to
// go onto the next player, which may be himself.
public void playTurn(View view) {
// Get the next participant in the game-defined way, possibly round-robin.
String nextParticipantId = getNextParticipantId();
// Get the updated state. In this example, we simply retrieve a
// text string from the view. In your game, there may be more
// complicated state.
mTurnData = mDataView.getText().toString();
// At this point, you might want to show a waiting dialog so that
// the current player does not try to submit turn actions twice.
showSpinner();
// Invoke the next turn. We are converting our data to a byte array.
Games.TurnBasedMultiplayer
.takeTurn(mGoogleApiClient, mMatch.getMatchId(),
mTurnData.getBytes(Charset.forName("UTF-16")),
nextParticipantId)
.setResultCallback(this);
}
Latest version of the jfxmobile plugin (1.0.3) includes recent changes in Dalvik SDK that contains the port of JavaFX 8 to android.
In FXActivity class, it has been added a very convenient method to listen to results of intents: setOnActivityResultHandler().
This means you shouldn't add new activities to your app, and only use FXActivity. You should add an Intent to it, and set a proper result handler to the FXActivity.
Have a look at this recent post at Gluon's site. It explains how to access native services, based on the case of taking a picture with the device's camera, and waiting to get the result of it to resume the app.
Basically, this is what it is required in this case:
public void takePicture() {
// create intent
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
...
// Add result handler
FXActivity.getInstance().setOnActivityResultHandler((requestCode, resultCode, data) -> {
if (requestCode == TAKE_PICTURE && resultCode == RESULT_OK) {
...
}
});
// launch activity
FXActivity.getInstance().startActivityForResult(intent, TAKE_PICTURE);
}
Try this approach with your app.
I am trying to figure out a clean and simple way to obtain the uid resulting from a call to createUser() when working with the Java SDK. This is easy to do when working with the Javascript SDK (e.g., this question/answer). I've also seen the question raised on Stackoverflow in the context of the Firebase iOS API where it apparently isn't so easy. My problem is how to do it using the Firebase Java SDK. Specifically, my use case is the same as that in the iOS-related question, i.e. allow an Admin user to create user accounts (email/password authentication) and also store other info about the created user in Firebase with the uid as the key. Knowing and using the uid as a key is essential in that it is the basis for the security rules.
I've seen a couple of proposed solutions, both of which involved some procedure to be carried out after the new user account has been created. These are
query the Firebase using the email address
Login as the new user and use the authData to get the uid
Either way I have a convoluted solution with multiple async callbacks to deal with an issue that is trivial when using the Javascript API.
I therefore have three specific questions:
Is there currently a better approach than the two I've listed above?
If I use the 2nd approach and login as the newly created user, doesn't that over-ride the Admin token (i.e., log-out the admin who created the user) which in turn means new security rules apply?
Is there any expectation that the Android & Java SDK's will be upgraded anytime soon so that the createUser() API is the same as the Javascript version?
UPDATE: Digging deeper and experimenting a bit I found the answers to my questions. It turns out that the API documentation provided by Firebase is out of date and/or inconsistent.
Re Q1: According to the Javadoc for createUser() the the only available callback handler is a Firebase.ResultHandler. However according to the Changelog, the API Reference document, and the documentation on Creating User Accounts, a Firebase.ValueResultHandler may be used as well. This provides direct access to the UID
Re Q2: The answer is yes. Authenticating the newly created user account results in the replacement of the auth token.
Re Q3: The real question should be "When are the Firebase folks going to update the Javadoc?" Or maybe a better question is "Why are new versions of the SDK being released without updated and accurate documentation?"
The following code is the correct way to deal with creating a new user
Firebase ref = new Firebase("https://<YOUR-FIREBASE>.firebaseio.com");
ref.createUser("harry#foo.com", "badPassword", new Firebase.ValueResultHandler<Map<String, Object>>() {
public void onSuccess(Map<String, Object> result) {
System.out.println("New account with uid: " + result.get("uid"));
}
public void onError(FirebaseError firebaseError) {
// there was an error
}
});
I've updated the question to explain the reasons.
Try this. This is for the newer version of Firebase that came out in the most recent Google I/O. I am not promoting this new version or putting the older version down. I am just stating this as an alternative to the solution above:
mAuth = FirebaseAuth.getInstance();
//creates the user with email and password...make this another type of login if you want
mAuth.createUserWithEmailAndPassword(mEmail, mPassword).addOnCompleteListener(signup.this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
//do something
}
}
});
Now you can add an AuthStateListener. You will have to put code in the onCreate, onStart, and onStop methods. Note that the above code can go in any reasonable method (e.g. onCreate, onStart, onResume, etc.). Here we go:
FirebaseAuth mAuth;
FirebaseAuth.AuthStateListener mAuthListener;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_something);
mAuth = FirebaseAuth.getInstance();
mAuthListener = new FirebaseAuth.AuthStateListener() {
#Override
public void onAuthStateChanged(#NonNull FirebaseAuth firebaseAuth) {
FirebaseUser user = firebaseAuth.getCurrentUser();
if(user != null){
//check for null to prevent NullPointerException when dealing with user
if(!user.getUid().matches("")){
//make this check just in case...I've experienced unexplainable glitches here
String uid = user.getUid();
//do more stuff with Uid
}
}
}
}
}
#Override
public void onStart(){
super.onStart();
mAuth.addAuthStateListener(mAuthListener);
}
#Override
public void onStop(){
super.onStop();
if(mListener != null){
mAuth.removeAuthStateListener(mAuthListener);
}
}
In the end, what happens is, once the user is created (and signed in at the same time), the mAuthListener makes a callback (it executes whatever is inside the mAuthListener, which, in this case, is getting the user's UID and doing other stuff with it). If you need help with this new Firebase in Android, here is a link to help you out: https://firebase.google.com/docs/android/setup