I made a messaging class extending FirebaseMessagingService and found that onNewToken method was working fine.
But, when I used the sample code for FirebaseMessaging class to get the current Firebase Token, I ran into an error: error: cannot find symbol method getToken().
What am I missing?
Any suggestion would be appreciated.
DataManager.java
import com.google.firebase.messaging.FirebaseMessaging;
import com.google.firebase.messaging.FirebaseMessagingService;
public class DataManager {
public static String registerGoogleServiceInBackground( final OnDataManagerRegisterGooglePlayServiceListener listener )
{
boolean isEnabledPlayService = true;
int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable( getContext() );
{
if( GooglePlayServicesUtil.isUserRecoverableError( resultCode ) )
{
GooglePlayServicesUtil.getErrorDialog( resultCode, (Activity) getContext(), PLAY_SERVICES_RESOLUTION_REQUEST ).show();
} else {
Log.i( "MainActivity.java|checkPlayService", "|This device is not supported.|" );
}
isEnabledPlayService = false;
}
if( isEnabledPlayService )
{
if( TextUtils.isEmpty( registrationId ) )
{
new AsyncTask<Void, Void, String>() {
#Override
protected String doInBackground( Void... params )
{
String msg;
try {
FirebaseMessaging.getInstance().getToken()
.addOnCompleteListener(new OnCompleteListener<String>() {
#Override
public void onComplete(#NonNull Task<String> task) {
if (!task.isSuccessful()) {
Log.w(tag, "Fetching FCM registration token failed", task.getException());
return;
}
// Get new FCM registration token
registrationId = task.getResult();
}
});
msg = "Device registered, registration ID=" + registrationId;
Log.d("Device registered", "|" + registrationId);
} catch( Exception ex ) {
msg = "Error :" + ex.getMessage();
}
return msg;
}
#Override
protected void onPostExecute( String msg ){
if( listener != null ) listener.onFinish( true, registrationId );
Log.i( "MainActivity.java | onPostExecute", "|" + msg + "|" );
}
}.execute( null, null, null );
return "";
}
} else {
if( listener != null ) listener.onFinish( true, registrationId );
return registrationId;
}
} else {
Log.i( "MainActivity.java | onCreate", "|No valid Google Play Services APK found.|" );
if( listener != null ) listener.onFinish( true, registrationId );
return null;
}
}
}
I think it has to do with firebase dependencies versions mismatch. Try to import the BoM for the Firebase platform. By using BoM your app will always use compatible versions of the Firebase Android libraries.
In your app-level build.gradle you can try add the following;
dependencies {
// Import the BoM for the Firebase platform
implementation platform('com.google.firebase:firebase-bom:28.3.0')
// Declare the dependencies for the Firebase Cloud Messaging and Analytics libraries
// When using the BoM, you don't specify versions in Firebase library dependencies
implementation 'com.google.firebase:firebase-messaging'
implementation 'com.google.firebase:firebase-analytics'
}
You can following the instructions here https://firebase.google.com/docs/cloud-messaging/android/client
Cheers!
I think like handsben above that the problem lies in the dependencies. I have an alternative suggestion that worked for me. This was the error message supplied by android studio
Cannot resolve method 'getToken' in 'FirebaseMessaging'
In the dependencies (in the app-level build.gradle) was this line
implementation 'com.google.firebase:firebase-messaging:20.1.0'
When I clicked on it android studio suggested I change it to
implementation 'com.google.firebase:firebase-messaging:23.0.5'
which I did and the error went away.
Hope this could work for you too
Related
I'm currently working on a chat application and I want to implement Parse Server Push notifications. I follow the documentation and put all the code that is required. My problem is that I can't see the notification, even though the console tells me that it was sent.
This is my MainActivity.java where is the Parse Installation.
#Override
protected void onCreate(Bundle savedInstanceState) {
notificationsPush();
createGraphicElements();
super.onCreate(savedInstanceState);
}
private void notificationsPush(){
ParseInstallation.getCurrentInstallation().saveInBackground(new SaveCallback() {
#Override
public void done(ParseException e) {
if (e == null){
System.out.println("---------------------");
System.out.println("SUCCESS ON INSTALLATION");
System.out.println("----------------------");
ParsePush.subscribeInBackground("Chat", new SaveCallback() {
#Override
public void done(ParseException e) {
if (e == null) {
System.out.println("----------------------");
System.out.println("SUCCESS ON CHANNEL");
System.out.println("----------------------");
} else {
System.out.println("----------------------");
System.out.println("ERROR ON CHANNEL: " + e.getMessage());
System.out.println("CODE: " + e.getCode());
System.out.println("----------------------");
}
}
});
}else{
System.out.println("---------------------");
System.out.println("ERROR ON INSTALLATION");
System.out.println("ERROR: " + e.getMessage());
System.out.println("CODE: " + e.getCode());
System.out.println("----------------------");
}
}
});
}
These are my implementations on graddle module. (There is also the one that is required to connect to Firebase).
implementation platform('com.google.firebase:firebase-bom:28.4.1')
implementation 'com.google.firebase:firebase-analytics'
implementation 'com.google.firebase:firebase-messaging'
//Parse Server
implementation "com.github.parse-community.Parse-SDK-Android:parse:1.26.0"
//PUSH Parse Server
implementation "com.github.parse-community.Parse-SDK-Android:fcm:1.26.0"
These are the functions that I use on my ParseCloud (they are on main.js).
Parse.Cloud.define("SendPush", function(request) {
var query = new Parse.Query(Parse.Installation);
query.exists("deviceToken");
// here you can add other conditions e.g. to send a push to sepcific users or channel etc.
var payload = {
alert: request.params.Message
// you can add other stuff here...
};
Parse.Push.send({
data: payload,
where: query
}, {
useMasterKey: true
})
.then(function() {
response.success("Push Sent!");
}, function(error) {
response.error("Error while trying to send push " + error.message);
});
});
Parse.Cloud.define("SendPush2", function(request) {
var msg = request.params.Message;
var query = new Parse.Query(Parse.User);
var user = request.params.user;
query.equalTo("objectId", user);
Parse.Push.send({
where: query,
data:{
alert: {
"title" : msg,
"body" : msg
},
sound: 'default'
}
}, {
useMasterKey: true,
success: function(){
response.success("Push Sent!");
},
error: function(error){
response.error("Error while trying to send push " + error.message);
}
});
});
Parse.Cloud.define("SendPush3", function(request, response) {
var userId = request.params.user;
var message = "sening a test message"; //request.params.message;
var queryUser = new Parse.Query(Parse.User);
queryUser.equalTo('objectId', userId);
var query = new Parse.Query(Parse.Installation);
query.matchesQuery('user', queryUser);
Parse.Push.send({
where: query,
data: {
alert: message,
badge: 0,
sound: 'default'
}
}, {
success: function() {
console.log('##### PUSH OK');
response.success();
},
error: function(error) {
console.log('##### PUSH ERROR');
response.error('ERROR');
},
useMasterKey: true
});
});
Finally, the piece of code of my app where I test those ParseCloud functions to send the notification.
private void sendMessage(){
if(messageEditText.getText().toString().length() > 0) {
String messageToSend = messageEditText.getText().toString();
messageEditText.setText("");
MessageBO messageBO = new MessageBO();
messageBO.setText(messageToSend);
messageBO.setUserIdSender(idUser);
messageBO.setUserIdReceiver(idContact);
insertMessage(messageBO.getUserIdSender().toString(),
messageBO.getUserIdReceiver().toString(),
messageBO.getText().toString());
enviarNotificacionPush(messageBO);
}
actualizarMensajes();
}
private void sendNotificationPush(MessageBO m){
HashMap<String,String> map = new HashMap<String, String>();
map.put("Message", m.getText().toString());
ParseCloud.callFunctionInBackground("SendPush",map, new FunctionCallback<Object>() {
#Override
public void done(Object object, ParseException e) {
if (e == null){
System.out.println("----------------------------");
System.out.println("NOTIFICATION SUCCES: " + object);
System.out.println("----------------------------");
}else{
System.out.println("----------------------------");
System.out.println("ERROR ON NOTIFICATION PUSH: " + e.getMessage());
System.out.println("CODE: " + e.getCode());
System.out.println("----------------------------");
}
}
});
HashMap<String,String> map2 = new HashMap<String, String>();
map2.put("Message", m.getText().toString());
map2.put("user", idUser);
ParseCloud.callFunctionInBackground("SendPush2",map2, new FunctionCallback<Object>() {
#Override
public void done(Object object, ParseException e) {
if (e == null){
System.out.println("----------------------------");
System.out.println("NOTIFICATION 2.0 SUCCESS: " + object);
System.out.println("----------------------------");
}else{
System.out.println("----------------------------");
System.out.println("ERROR ON NOTIFICATION PUSH 2.0: " + e.getMessage());
System.out.println("CODE: " + e.getCode());
System.out.println("----------------------------");
}
}
});
ParseCloud.callFunctionInBackground("SendPush3",map2, new FunctionCallback<Object>() {
#Override
public void done(Object object, ParseException e) {
if (e == null){
System.out.println("----------------------------");
System.out.println("NOTIFICACION 3.0 SUCCESS: " + object);
System.out.println("----------------------------");
}else{
System.out.println("----------------------------");
System.out.println("ERROR ON NOTIFICACION PUSH 3.0: " + e.getMessage());
System.out.println("CODE: " + e.getCode());
System.out.println("----------------------------");
}
}
});
}
As you can see, I use 3 functions that send notifications, all of them said that it was a success, but in my android emulator never arrive a notification. I check my parse Dashboard and even though that it says that the notifications were sent, it also says 0 deliveries. I need your help please because I don't know exactly what I'm doing wrong.
If you need, the info of my Android emulator is the following:
My android emulator info
[EDIT 1]
(I don't know how to refer the comment that ask me to do it but anyways) Because I see that maybe you'll need the installation class.
installation class
All installations are from the emulator due to I uninstall and install again the application. There is algo my smartphone, that is a Huawei (that also I can't see notifications but I know thats due to Huawei problems with google services).
[EDIT 2]Hello again, here is my Parse Server configuration(aka the index.js of my parse). I'm using the parse_server_example repository by the way.
// Example express application adding the parse-server module to expose Parse
// compatible API routes.
const express = require('express');
const ParseServer = require('parse-server').ParseServer;
const path = require('path');
var ParseDashboard = require('parse-dashboard');
const args = process.argv || [];
const test = args.some(arg => arg.includes('jasmine'));
const databaseUri = process.env.DATABASE_URI || process.env.MONGODB_URI;
if (!databaseUri) {
console.log('DATABASE_URI not specified, falling back to localhost.');
}
const config = {
databaseURI: databaseUri || 'mongodb://admin:123#localhost:27017/ParseServer?authSource=admin',
cloud: process.env.CLOUD_CODE_MAIN || __dirname + '/cloud/main.js',
appId: process.env.APP_ID || 'MY_APP_ID',
masterKey: process.env.MASTER_KEY || 'MY_MASTER_KEY', //Add your master key here. Keep it secret!
serverURL: process.env.SERVER_URL || 'http://192.168.10.100:1337/parse/', // Don't forget to change to https if needed
liveQuery: {
classNames: ['Posts', 'Comments'], // List of classes to support for query subscriptions
},
push: {
android: {
apiKey: 'AAAASP09btg:APA91bGxn3e0vJX0ri2DeFEWUjAODTCaP3mfCQ0la3oiIgNqNYUlj2THFlEwRjqnXGuI-8H_l5-0xZtyscn3yY4mRrAL5tNHYXrM8NBltgCwCx1gH8LFVvgAWubmV2Zsa5NkmD53vCeO'
}
}
};
// Client-keys like the javascript key or the .NET key are not necessary with parse-server
// If you wish you require them, you can set them as options in the initialization above:
// javascriptKey, restAPIKey, dotNetKey, clientKey
var configdashboard = {
"allowInsecureHTTP": true,
"apps": [
{
"serverURL": "http://192.168.10.100:1337/parse/",
"appId": "MY_APP_ID",
"masterKey": "MY_MASTER_KEY",
"appName": "ParseServer01"
}
],"users": [
{
"user": "root",
"pass": "123456"
}
]
};
var dashboard = new ParseDashboard(configdashboard,{allowInsecureHTTP:configdashboard.allowInsecureHTTP});
const app = express();
app.use('/dashboard', dashboard);
// Serve static assets from the /public folder
app.use('/public', express.static(path.join(__dirname, '/public')));
// Serve the Parse API on the /parse URL prefix
const mountPath = process.env.PARSE_MOUNT || '/parse';
if (!test) {
const api = new ParseServer(config);
app.use(mountPath, api);
}
// Parse Server plays nicely with the rest of your web routes
app.get('/', function (req, res) {
res.status(200).send('I dream of being a website. Please star the parse-server repo on GitHub!');
});
// There will be a test page available on the /test path of your server url
// Remove this before launching your app
app.get('/test', function (req, res) {
res.sendFile(path.join(__dirname, '/public/test.html'));
});
const port = process.env.PORT || 1337;
if (!test) {
const httpServer = require('http').createServer(app);
httpServer.listen(port, function () {
console.log('parse-server-example running on port ' + port + '.');
});
// This will enable the Live Query real-time server
ParseServer.createLiveQueryServer(httpServer);
}
module.exports = {
app,
config,
};
[EDIT 3] Hello again, I was trying to send notifications with curl and this is what happens:
curl -X POST \
-H "X-Parse-Application-Id: wPacsFQMmP" \
-H "X-Parse-Master-Key: DwonoEbeNf" \
-H "Content-Type: application/json" \
-d '{
"where": {
"deviceType": {
"$in": [
"android"
]
}
},
"data": {
"title": "The Shining",
"alert": "All work and no play makes Jack a dull boy."
}
}'\ http://192.168.10.100:1337/parse/push
{"result":true}[
Also as additional info, when I try making a push using FCM only (that means, follow this Firebase FCM documentation) and the result is basically the same, it says it was sent succesfully but I don't see it on the android emulator, not even in my old smartphone (Nokia 6).
[EDIT 4] I turn on verbose, and this is what I found in my parse logs about SendPush cloud function.
REQUEST for [POST] /parse/push: {\\n \\\"channels\\\": [\\n \\\"SignChat\\\"\\n ],\\n \\\"data\\\": {\\n \\\"alert\\\": \\\"The Giants won against the Mets 2-3.\\\"\\n }\\n}\",\n \"method\": \"POST\",\n \"timestamp\": \"2021-10-28T20:25:27.623Z\",\n \"url\": \"/parse/push\"\n },\n {\n \"level\": \"verbose\",\n \"message\": \"RESPONSE from [POST] /parse/functions/SendPush: {\\n \\\"response\\\": {}\\n}\",\n \"result\": {\n \"response\": {}\n },\n \"timestamp\": \"2021-10-28T20:25:27.619Z\"\n }
To send push notifications for Android devices, the required fields are deviceToken and GCMSenderID.
However, according to the screenshot you sent, the GCMSenderId of your installations is empty, and it's required for sending push notifications.
In your MainActivity, you're not explicitly set it, which is needed to save it properly.
Here's a sample code showing how you can do that:
ParseInstallation installation = ParseInstallation.getCurrentInstallation();
installation.put("GCMSenderId", INSERT_YOUR_SENDER_ID);
installation.saveInBackground();
Once both fields are filled, the push notification might work properly.
I'm getting error for phone authentication. I received OTP successfully, but after I share my project with my team member with GitHub, I'm getting this errors.
I also I added MY SHA 1 & SHA 256 in my new firebase console. I also added dependencies, but still I get this error.
I also want to inform that after transfer my project with GitHub, I make new firebase account and add SHA 1 & SHA 256 in this project
Logcat:
03-16 16:19:40.001 8163-8163/com.roundtripride E/zzf: Problem retrieving SafetyNet Token: 7:
03-16 16:19:40.679 8163-8235/com.roundtripride E/FirebaseAuth: [GetAuthDomainTask] Error getting project config. Failed with INVALID_CERT_HASH 400
03-16 16:19:40.713 8163-8163/com.roundtripride E/zzf: Failed to get reCAPTCHA token with error [There was an error while trying to get your package certificate hash.]- calling backend without app verification
03-16 16:19:41.202 8163-8201/com.roundtripride E/FirebaseAuth: [SmsRetrieverHelper] SMS verification code request failed: unknown status code: 17093 null
03-16 16:19:41.202 8163-8163/com.roundtripride E/Tag: onVerificationFailed : This request is missing a valid app identifier, meaning that neither SafetyNet checks nor reCAPTCHA checks succeeded. Please try again, or check the logcat for more details.
03-16 16:19:41.202 8163-8163/com.roundtripride E/Tag: onVerificationFailed : This request is missing a valid app identifier, meaning that neither SafetyNet checks nor reCAPTCHA checks succeeded. Please try again, or check the logcat for more details.
03-16 16:19:41.202 8163-8163/com.roundtripride E/Tag: onVerificationFailed : com.google.firebase.auth.FirebaseAuthException: This request is missing a valid app identifier, meaning that neither SafetyNet checks nor reCAPTCHA checks succeeded. Please try again, or check the logcat for more details.
Dependencies:
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.3.0'
implementation 'com.google.android.gms:play-services-maps:17.0.0'
implementation 'com.google.android.gms:play-services-location:18.0.0'
implementation 'com.google.android.libraries.places:places:2.4.0'
implementation platform('com.google.firebase:firebase-bom:26.7.0')
implementation 'com.google.firebase:firebase-analytics'
implementation 'com.google.firebase:firebase-auth:20.0.3'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
implementation 'com.nostra13.universalimageloader:universal-image-loader:1.9.5'
implementation 'com.intuit.sdp:sdp-android:1.0.6'
implementation 'de.hdodenhof:circleimageview:3.1.0'
implementation 'com.amitshekhar.android:jackson-android-networking:1.0.2'
implementation 'com.github.prolificinteractive:material-calendarview:1.6.0'
implementation 'androidx.browser:browser:1.3.0'
implementation 'com.google.firebase:firebase-messaging'
implementation 'com.google.android.gms:play-services-safetynet:17.0.0'
}
Code:
public class OTPVerifyActivity extends BaseActivity implements View.OnClickListener {
Context context;
private FirebaseAuth mAuth;
private String mVerificationId;
String idToken = "", mobile;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_otp_verify);
Utility.setLoginStatusColor(this);
context = this;
txt_finish = findViewById(R.id.txt_finish);
edt_1 = findViewById(R.id.edt_1);
mAuth = FirebaseAuth.getInstance();
mobile = getIntent().getStringExtra("mobile");
sendVerificationCode();
txt_finish.setOnClickListener(this);
}
#Override
public void onClick(View view) {
if (view == txt_finish) {
Utility.hideSoftKeyboard(edt_1, context);
if (edt_1.getText().toString().equals("")) {
Utility.errDialog("Please enter OTP", context);
} else {
verifyVerificationCode(edt_1.getText().toString().trim());
}
}
}
private void sendVerificationCode() {
PhoneAuthOptions options =
PhoneAuthOptions.newBuilder(mAuth)
.setPhoneNumber("+91" + mobile) // Phone number to verify
.setTimeout(30L, TimeUnit.SECONDS) // Timeout and unit
.setActivity(this) // Activity (for callback binding)
.setCallbacks(mCallbacks) // OnVerificationStateChangedCallbacks
.build();
PhoneAuthProvider.verifyPhoneNumber(options);
}
private PhoneAuthProvider.OnVerificationStateChangedCallbacks mCallbacks = new PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
#Override
public void onVerificationCompleted(PhoneAuthCredential phoneAuthCredential) {
Log.e("Tag", "get Data : " + phoneAuthCredential.getSmsCode());
Utility.dismissProgressDialog(pd);
String code = phoneAuthCredential.getSmsCode();
if (code != null) {
edt_1.setText(code);
verifyVerificationCode(code);
}
}
#Override
public void onVerificationFailed(FirebaseException e) {
Utility.dismissProgressDialog(pd);
Log.e("Tag", "onVerificationFailed : " + e.getMessage());
Log.e("Tag", "onVerificationFailed : " + e.getLocalizedMessage());
Log.e("Tag", "onVerificationFailed : " + e.toString());
Utility.errDialog(e.getMessage(), context);
}
#Override
public void onCodeSent(String s, PhoneAuthProvider.ForceResendingToken forceResendingToken) {
super.onCodeSent(s, forceResendingToken);
mVerificationId = s;
Utility.dismissProgressDialog(pd);
}
};
private void verifyVerificationCode(String code) {
//Log.e("Tag","Verify code : "+code);
pd = Utility.showProgressDialog(context);
try {
PhoneAuthCredential credential = PhoneAuthProvider.getCredential(mVerificationId, code);
signInWithPhoneAuthCredential(credential);
} catch (Exception e) {
Log.e("Tag", "PhoneAuthCredential Exception " + e.getMessage());
}
}
private void signInWithPhoneAuthCredential(PhoneAuthCredential credential) {
mAuth.signInWithCredential(credential)
.addOnCompleteListener(OTPVerifyActivity.this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
FirebaseUser user = mAuth.getCurrentUser();
user.getIdToken(true)
.addOnCompleteListener(new OnCompleteListener<GetTokenResult>() {
public void onComplete(#NonNull Task<GetTokenResult> task) {
if (task.isSuccessful()) {
idToken = task.getResult().getToken();
Utility.dismissProgressDialog(pd);
Log.e("Tag", "Success OTP " + isDriver);
MyPreference.setPreferenceValue(context,"isLogin","true");
}
}
});
} else {
Utility.dismissProgressDialog(pd);
//verification unsuccessful.. display an error message
String message = "Something is wrong, we will fix it soon...";
if (task.getException() instanceof FirebaseAuthInvalidCredentialsException) {
message = "Invalid code entered...";
}
Log.e("Tag", message);
Utility.errDialog(message, context);
}
}
});
}
}
Remove your debug SHA-1 and SHA-256 from your old firebase account .
Open android studio and click on gradle in right corner > click your project > select app > select tasks > select android > click on signing report > copy our SHA1 and SHA-256 from there.
Add SHA1 and SHA-256 in your new firebase account .(if you are building apk from 2 system add both system's SHA1 and SHA-256).
You need to make sure that you enabled PHONE AUTHENTICATION in Firebase console => Authentication => Sign-in Methods.
Add dependency in build.gradle(:app)
implementation 'androidx.browser:browser:1.3.0'
Go to google cloud console , select your project .
Click on navigation menu and select APis & services and then select Dashboard .
Click on enable api and services and enable api " Android Device Verification".
Download and replace the latest google-services.json file in your project.
implementation 'androidx.browser:browser:1.3.0'
please add this dependency then check sha1 and sha256 one more time then try it
implementation 'com.google.firebase:firebase-config:11.8.0'
FirebaseRemoteConfig mFirebaseRemoteConfig = FirebaseRemoteConfig.getInstance();
FirebaseRemoteConfigSettings configSettings = new FirebaseRemoteConfigSettings.Builder()
.setDeveloperModeEnabled(BuildConfig.DEBUG)
.build();
mFirebaseRemoteConfig.setConfigSettings(configSettings);
mFirebaseRemoteConfig.fetch(0).addOnCompleteListener(this, new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
mFirebaseRemoteConfig.activateFetched();
String appDefaultColor = mFirebaseRemoteConfig.getString(FIREBASE_REMOTE_CONFIG_DEFAULT_COLOR);
if (appDefaultColor != null && appDefaultColor.length() > 0) {
System.out.println("==== appDefaultColor : " + appDefaultColor);
}
}
}
});
public static String FIREBASE_REMOTE_CONFIG_DEFAULT_COLOR = "project_default_theme_color";
here is my implementation of Firebase remote config.
As above my code explanation, project4_default_theme_color, i get the value from firebase, But the situation is that i change that value from Firebase remote config , but i did't get.
My firebase remote config Key project_default_theme_color and value is #f04030 and Publish Changes.is any wrong in this?
Follow below instruction to resolve this issue
Update your firebase library version
implementation 'com.google.firebase:firebase-config:19.1.0'
implementation 'com.google.firebase:firebase-core:17.2.1'
Initialize FirebaseRemoteConfig
FirebaseRemoteConfig firebaseRemoteConfig = FirebaseRemoteConfig.getInstance();
Set firebaseRemoteConfig parameter default value
firebaseRemoteConfig.setDefaultsAsync(R.xml.remote_config_defaults);
Add below code in remote_config_defaults.xml
<?xml version="1.0" encoding="utf-8"?>
<defaultsMap>
<entry>
<key>your_key</key>
<value>defaultValue</value>
</entry>
Add this code in your java file
firebaseRemoteConfig.fetch(cacheTimeDuration)
.addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
String errorString = "";
if (task.isSuccessful()) {
firebaseRemoteConfig.activate();
errorString = " task is successful ";
} else {
errorString = "task is canceled";
}
Log.i(TAG, "onComplete: error " + errorString);
Log.i(TAG, " Get firebase remote config value " + firebaseRemoteConfig.getString("your_key"));
}
});
Note :
If your Apk is debug then use this method .fetch(cacheTimeDuration)
If your Apk is Release then use this method .fetch()
Take a look at the code below. This is server-side. I call the Google ReCaptcha API with bad secret key and bad user token response, as you can see. You know what? It works! More precisely: Google ReCaptcha API doesn't answer with exception (i.e.: my catch isn't reached). Why? This is not the expected behavior, right?
/**
* Verifies a Recaptcha filled by the user in his Android app.
* 1. Success: returns the JSON response
* 2. Failure: throws the error
**/
exports.verifyRecaptcha = functions.https.onCall((data, context) => {
const user_response_token = data.userResponseToken;
if(user_response_token === null || user_response_token === '') {
throw new functions.https.HttpsError('invalid-argument', 'The function must be called with an adequat user response token.');
}
const remote_url = 'https://recaptcha.google.com/recaptcha/api/siteverify';
const secret = '<MY_REAL_SECRET_KEY>'; // Original value: 'https://www.google.com/recaptcha/api/siteverify'; # Moises' value: https://recaptcha.google.com/recaptcha/api/siteverify
var options = {
method: 'POST',
uri: remote_url,
body: {secret: 'Foo', response: 'Bar'},
// body: {secret: secret, response: user_response_token},
json: true
};
return rp(options)
.then(parsedBody => {
return {code: 'Success', message: 'You are actually a human (this msg is for test purposes).'};
})
.catch(error => {
throw new functions.https.HttpsError('unknown', error);
});
});
And below is the Android app code:
final SafetyNetApi.RecaptchaTokenResponse response = task.getResult();
assert response != null;
final String userResponseToken = response.getTokenResult();
if (!userResponseToken.isEmpty()) {
final HashMap<String, String> the_data = new HashMap<>();
the_data.put("userResponseToken", userResponseToken);
FirebaseFunctions.getInstance()
.getHttpsCallable("verifyRecaptcha")
.call(the_data)
.continueWith(new Continuation<HttpsCallableResult, Void>() {
#Override
public Void then(#NonNull final Task<HttpsCallableResult> task) {
if(context.isDestroyed() || context.isFinishing()) {
return null;
}
if(!task.isSuccessful()) {
Exception e = task.getException();
if (e instanceof FirebaseFunctionsException) {
FirebaseFunctionsException ffe = (FirebaseFunctionsException) e;
System.out.println(ffe.getMessage());
}
return null;
}
callback.onAsking();
return null;
}
});
} else {
callback.onFailureUserResponseTokenIsEmpty();
}
The docs suggest that errors such as invalid-input-secret/invalid-input-response will appear in the error-codes field of the response.
This information doesn't necessarily need to be translated into an HTTP error code (which would cause your catch block to execute); in this instance, Google apparently wanted to support multiple simultaneous error messages, and the HTTP response code pertains more to the conduct of the protocol at the HTTP level.
While we're looking at the docs, I should point out that you probably want to refer to the success field before presuming that your user is a human.
I made a function in my Cloud Functions to verify a purchase signature. It must return a boolean and a string value. I read on Firebase Cloud Functions documentation that I should return a JSON structure that contains all the values. I made it like this.
EDIT
This is my entire Cloud Functions:
const BASE_64_ENCODED_PUBLIC_KEY = "MY_PUBLIC_KEY_HERE"
const KEY_FACTORY_ALGORITHM = "RSA-SHA1";
// The Cloud Functions for Firebase SDK to create Cloud Functions and setup triggers.
const functions = require('firebase-functions');
const crypto = require('crypto');
exports.verifySignature = functions.https.onCall((data, context) => {
const purchaseJSON = data.signedData;
const signature = data.signature;
console.log("start verification");
if (purchaseJSON === null || signature === null) {
console.log("Purchase verification failed: missing data.");
return {
message: "missing data",
verified: false
}
}
const verifier = crypto.createVerify(KEY_FACTORY_ALGORITHM);
verifier.update(purchaseJSON);
if (verifier.verify(publicKey, signature, "base64")){
console.log("signature verification success!");
return {
message: "verification success",
verified: true
}
} else {
console.log("signature verification failed!");
return {
message: "verification failed",
verified: false
};
}
});
And this is my code on the client:
private Task<String> verifyValidSignature(String signedData, String signature) {
// Create the arguments to the callable function.
Map<String, Object> data = new HashMap<>();
data.put("signedData", signedData);
data.put("signature", signature);
return mFunctions.getHttpsCallable("verifySignature")
.call(data)
.continueWith(new Continuation<HttpsCallableResult, String>() {
#Override
public String then(#NonNull Task<HttpsCallableResult> task) throws Exception {
HttpsCallableResult result = task.getResult();
if (result != null) {
return result.getData().toString();
}
return null;
}
});
}
How can I get the message value and convert it to a string and the verified value and convert it to a boolean in Android/Java?
result.getData() is returning a Map type object, because you returned an object from the function. JavaScript objects become Java Maps. You just use it like you would any other Map.
Map<String, Object> data = (Map<String, Object>) result.getData();
String message = (String) data.get("message");
boolean verified = (Boolean) data.get("verified");
What you are doing is ok, the only thing missing is to promosify it, this would do the trick
return Promise.resolve({ message: “verification success”, verified: true })
Similar for the error case but instead of using Promise.resolve you will use Promise.reject