No data is stored in Firebase Database [duplicate] - kotlin

I am trying to save user credentials to Firebase Realtime Database. However, when I execute the program, the DB does not update. I have configured the Firebase setup correctly as Authentication and Storage (both Firebase) are working.
build.gradle:
dependencies {
...
// Firebase SDK setup
// Import the BoM for the Firebase platform
implementation platform('com.google.firebase:firebase-bom:28.0.1')
// Declare the dependency for the Firebase library
implementation 'com.google.firebase:firebase-storage-ktx'
implementation 'com.google.firebase:firebase-auth-ktx'
implementation 'com.google.firebase:firebase-database-ktx'
}
apply plugin: 'com.google.gms.google-services'
AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package=<NAME>>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
...
</application>
</manifest>
The registration class (MWE):
class RegisterActivity : AppCompatActivity() {
var selectedPhotoUri: Uri? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Register UI
register_button_register.setOnClickListener {
performRegister()
}
}
// Register user credentials
private fun performRegister() {
val email = email_editText_register.text.toString()
val password = password_editText_register.text.toString()
// Firebase Authentication - WORKING
FirebaseAuth.getInstance().createUserWithEmailAndPassword(email, password)
.addOnCompleteListener {
uploadImageToFirebaseStorage()
}
}
// Upload selected photo to Firebase Storage - WORKING
private fun uploadImageToFirebaseStorage() {
if(selectedPhotoUri == null) return
val filename = UUID.randomUUID().toString()
val ref = FirebaseStorage.getInstance().getReference("/images/$filename")
ref.putFile(selectedPhotoUri!!)
ref.downloadUrl.addOnSuccessListener {
saveUserToFirebaseDatabase(it.toString())
}
}
// Save user associated credentials to Firebase Database - NOT WORKING
private fun saveUserToFirebaseDatabase(profileImageURL: String) {
val uid = FirebaseAuth.getInstance().uid ?: ""
val ref = Firebase.database.getReference("/users/$uid")
val user = User(uid, username_editText_register.text.toString(), profileImageURL)
ref.setValue(user)
}
}
// User credentials to be saved
class User(val uid: String, val username: String, val profileImageURL: String)
The saveUserToFirebaseDatabase() method does not get executed? I have checked logcat after inserting onSuccessListener and onFailureListener statements, however no error or debug information is highlighted. The app. pushes the image to storage but the DB is not updated. It remains empty. The workflow is as:
- Authenticate user by email and password. - WORKING
- Save profile image in Storage. - WORKING
- Save profile identifier, username, and image in DB. - NOT WORKING
Firebase DB rules:
{
"rules": {
".read": "true",
".write": "true"
}
}
I tried changing the hierarchy but that did not work either:
val uid = FirebaseAuth.getInstance().uid ?: ""
val ref = Firebase.database.getReference("/users/$uid")
val user = User(uid, username_edittext_register.text.toString(), profileImageUrl)
ref.child("users").child(uid).setValue(user)
I have read the Firebase documentation and everything seems to be in place. I also disabled my firewall but that did not work either. Can someone point out the problem here? Thank you in advance.

To get a reference to a Firebase Realtime Database other than the (default) "us-central1", for instance "europe-west1", you must pass the database URL to the getInstance() method.
For "us-central1" there is no need for doing that, you can simply call the "getInstance()" method without passing any arguments.
For more info, please check the official documentation regarding Realtime Database locations:
https://firebase.google.com/docs/projects/locations#rtdb-locations
As an alternative solution, you can download an up-to-date google-services.json from the Firebase Console and add it to your app. If the correct URL of the location is in there, the SDK will read it from there when you call FirebaseDatabase.getInstance() without passing any arguments.

Related

Missing Feature{name=auth_api_credentials_begin_sign_in, version=6}

I am trying to use the Google authentication method (One tap sign in) for my application. However, after I clicked on the sign button, I faced the following problems:
W/GoogleApiManager: com.google.android.gms.internal.auth-api.zbaz could not execute call because it requires feature (auth_api_credentials_begin_sign_in, 6).
D/btn click: Missing Feature{name=auth_api_credentials_begin_sign_in, version=6}.
May I know where have I messed up?
I am using MsSQL instead of firebase.
I have created the OAuth 2.0 client.
I am using the Web Client ID for the BuildConfig (I have both Web Client and Android)
buildConfigField : ("String", "CLIENT_ID", '"1113838514547 -neqok16gfh5b77v6hcg33c03d0khs896.apps.googleusercontent.com"')
The google Sign in button was not working with viewBinding so I swapped to "findViewById" for that particular button
Below are the codes:
import android.content.IntentSender
import android.os.Bundle
import android.util.Log
import androidx.activity.result.IntentSenderRequest
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import com.example.myapplication.databinding.ActivitySignInBinding
import com.google.android.gms.auth.api.identity.BeginSignInRequest
import com.google.android.gms.auth.api.identity.Identity
import com.google.android.gms.auth.api.identity.SignInClient
import com.google.android.gms.common.SignInButton
import com.google.android.gms.common.api.ApiException
import com.google.android.gms.common.api.CommonStatusCodes
import com.google.android.material.snackbar.Snackbar
class MainLoginActivity : AppCompatActivity() {
private var _binding: ActivitySignInBinding? = null
private val binding get() = _binding!!
private var sign_in_button : SignInButton? = null
private var oneTapClient: SignInClient? = null
private var signUpRequest: BeginSignInRequest? = null
private var signInRequest: BeginSignInRequest? = null
private val oneTapResult = registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()){ result ->
try {
val credential = oneTapClient?.getSignInCredentialFromIntent(result.data)
val idToken = credential?.googleIdToken
when {
idToken != null -> {
// Got an ID token from Google. Use it to authenticate
// with your backend.
val msg = "idToken: $idToken"
Snackbar.make(binding.root, msg, Snackbar.LENGTH_INDEFINITE).show()
Log.d("one tap", msg)
}
else -> {
// Shouldn't happen.
Log.d("one tap", "No ID token!")
Snackbar.make(binding.root, "No ID token!", Snackbar.LENGTH_INDEFINITE).show()
}
}
} catch (e: ApiException) {
when (e.statusCode) {
CommonStatusCodes.CANCELED -> {
Log.d("one tap", "One-tap dialog was closed.")
// Don't re-prompt the user.
Snackbar.make(binding.root, "One-tap dialog was closed.", Snackbar.LENGTH_INDEFINITE).show()
}
CommonStatusCodes.NETWORK_ERROR -> {
Log.d("one tap", "One-tap encountered a network error.")
// Try again or just ignore.
Snackbar.make(binding.root, "One-tap encountered a network error.", Snackbar.LENGTH_INDEFINITE).show()
}
else -> {
Log.d("one tap", "Couldn't get credential from result." +
" (${e.localizedMessage})")
Snackbar.make(binding.root, "Couldn't get credential from result.\" +\n" +
" (${e.localizedMessage})", Snackbar.LENGTH_INDEFINITE).show()
}
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
_binding = ActivitySignInBinding.inflate(layoutInflater)
setContentView(binding.root)
sign_in_button = findViewById(R.id.sign_in_button)
oneTapClient = Identity.getSignInClient(this)
signUpRequest = BeginSignInRequest.builder()
.setGoogleIdTokenRequestOptions(
BeginSignInRequest.GoogleIdTokenRequestOptions.builder()
.setSupported(true)
// Your server's client ID, not your Android client ID.
.setServerClientId(BuildConfig.CLIENT_ID)
// Show all accounts on the device.
.setFilterByAuthorizedAccounts(false)
.build())
.build()
signInRequest = BeginSignInRequest.builder()
.setGoogleIdTokenRequestOptions(
BeginSignInRequest.GoogleIdTokenRequestOptions.builder()
.setSupported(true)
// Your server's client ID, not your Android client ID.
.setServerClientId(BuildConfig.CLIENT_ID)
// Show all accounts on the device.
.setFilterByAuthorizedAccounts(true)
.build())
.setAutoSelectEnabled(true)
.build()
sign_in_button!!.setOnClickListener{
displaySignIn()
}
}
private fun displaySignIn(){
oneTapClient?.beginSignIn(signInRequest!!)
?.addOnSuccessListener(this) { result ->
try {
val ib = IntentSenderRequest.Builder(result.pendingIntent.intentSender).build()
oneTapResult.launch(ib)
} catch (e: IntentSender.SendIntentException) {
Log.e("btn click", "Couldn't start One Tap UI: ${e.localizedMessage}")
}
}
?.addOnFailureListener(this) { e ->
// No Google Accounts found. Just continue presenting the signed-out UI.
displaySignUp()
Log.d("btn click", e.localizedMessage!!)
}
}
private fun displaySignUp() {
oneTapClient?.beginSignIn(signUpRequest!!)
?.addOnSuccessListener(this) { result ->
try {
val ib = IntentSenderRequest.Builder(result.pendingIntent.intentSender).build()
oneTapResult.launch(ib)
} catch (e: IntentSender.SendIntentException) {
Log.e("btn click", "Couldn't start One Tap UI: ${e.localizedMessage}")
}
}
?.addOnFailureListener(this) { e ->
// No Google Accounts found. Just continue presenting the signed-out UI.
displaySignUp()
Log.d("btn click", e.localizedMessage!!)
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.gms.common.SignInButton
android:id="#+id/sign_in_button"
android:layout_width="129dp"
android:layout_height="52dp"
android:layout_marginStart="141dp"
android:layout_marginTop="252dp"
android:layout_marginEnd="141dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
I was banging my head against the wall for a few days on this issue and finally Alex Mamo helped me solve it. A few things could have caused this issue. First, ensure the following:
User is logged in on a Google account on the emulator.
Both SHA-1 and SHA-256 debug fingerprints are added to the correct project.
The correct google-services.json file is in the correct directory.
The web_client_id is yours and passed correctly into the required fields.
Then if nothing changed, try running the app on a real Android device. By real I mean a device that has been used by real people for some real time and not just a demo physical device conveniently sitting right next you.
If your app still produces the same error, then there are some other issues with the app that I unfortunately cannot help with.
If your app functions correctly on a real device, then it means your emulator is not set up properly. Try spinning up a new emulator and going through the new device configuration process (for me it was called "Setting Up Your Device" and it was available as an actionable notification bar button). This is a separate/different process than simply signing into a Google Account on your Android device. Once complete, wait ten minutes and reboot for good measure. This solved my issue.
Hope this helps!
I got the same error while trying to SignIn using my Android Studio emulator. The problem was a version incompatibility with some plugins.
Broken project build gradle:
id 'com.android.application' version '7.1.3' apply false
id 'com.android.library' version '7.1.3' apply false
Fix:
id 'com.android.application' version '7.1.2' apply false
id 'com.android.library' version '7.1.2' apply false
Furthermore, download again the google-services.json file. It should solve the problem.
Edit: got again the problem and I found out that it is a problem of incompatibility between the API and the version of the emulator. Installing an emulator with API 31 (instead of 32) definitely solved the problem.
In addition to the requirements mentioned by Endian Tribe in his answer, I also had to ensure the following in order to get rid of the error on my emulator:
Use a Google Play system image (Google APIs image didn't work for me).
Set a lock screen pattern or PIN.
Apply any pending system updates (did this via Settings -> Security -> Security/Google Play system update on Android 12).
Not sure if all 3 steps are required but that's what did the trick for me.
In my case I have correct firebase setup (tested before and it worked on same emulator).
Also I've done all steps with authorization in google on device, setup PIN and check for system and google play updates. Nothing changed.
To solve problem I have to manually clear data in Google app on emulator. Then auth in my app worked.
For me the error disappeared in the emulator after installing the Google Play services update as indicated in the screenshots below.
First create an emulator that supports Google Play as "Pixel_4_API_R" or "Pixel_3a_API_28" (see screenshot 1).
Then start the emulator and open the Extended Controls window. There go to "Google Play" and select "Update" (see screenshot 2).
After clicking on the Update button I had to enter a google credential on the phone emulator.
After entering the credentials and confirming a few screens the update of google play services did start automatically on one emulator and on another I had to click the update button again.
Screenshot 1
Screenshot 2

MongoDB Database is not created in Kotlin(Ktor)

please i need help with connecting a mongodb to my ktor application.
This is the code i have, as followed from this article: https://himanshoe.com/mongodb-in-ktor
class MongoDataHandler {
val client = KMongo.createClient().coroutine
val database = client.getDatabase("dev")
val userCollection = database.getCollection<User>()
suspend fun adduser(email: String, username: String, password: String): User? {
userCollection.insertOne(User(userId = null, email = email, userName = username, passwordHash = password))
return userCollection.findOne(User::email eq email )
}
suspend fun finduser(id: String): User?{
return userCollection.findOneById(id)
}
}
I installed mongodb as directed from their website. The mongodb is started as a service upon successful install. I run this command "C:\Program Files\MongoDB\Server\5.0\bin\mongo.exe" to use the mongodb. When i check for the available database using "show dbs", i realize that my database(dev) is not listed.
This is the dependency am using:
implementation("org.litote.kmongo:kmongo-coroutine:4.2.8")
And this the the error i am getting:
[eventLoopGroupProxy-4-1] INFO Application - 500 Internal Server Error:
POST - /user
I guess i am doing something wrong... thanks in advance
Try to change your MongoDataHandler to the following, using the MongoClients.create() method, and adding a codecRegistry to your client.
You will not need the connection string settings if you are using the local connection with the default settings:
class MongoDataHandler {
private val database: MongoDatabase
private val usersCollection: MongoCollection<User>
init {
val pojoCodecRegistry: CodecRegistry = fromProviders(
PojoCodecProvider.builder()
.automatic(true)
.build()
)
val codecRegistry = fromRegistries(MongoClientSettings.getDefaultCodecRegistry(), pojoCodecRegistry)
val settings: MongoClientSettings = MongoClientSettings.builder()
// .applyConnectionString("localhost") => add the connection string if not using localhost
.codecRegistry(codecRegistry)
.build()
val mongoClient = MongoClients.create(settings)
database = mongoClient.getDatabase("dev")
usersCollection = database.getCollection(User::class.java.name, User::class.java)
}
Also, if you are not using docker, try to use docker-compose to orchestrate your mongodb container:
version: '3'
services:
mongo:
image: mongo:latest
ports:
- "27017:27017"
If you want a running example with Ktor/MongoDB take a look in this project
I assume you are in development mode and trying this in our local machine.
Make sure you have MongoDB installed on the local machine and the local server is running well. Here is a guide for ubuntu.
After successful setup and installation of MongoDB, run this command
mongo --eval 'db.runCommand({ connectionStatus: 1 })'
The output should contain a line as below:
connecting to : mongodb://127.0.0.1:27017/?compressors=disabled&gssapiServiceName=mongodb
Make sure to add this line while creating client in the ConnectionString like:\
private val client = KMongo.createClient(
ConnectionString("mongodb://127.0.0.1:27017")
).coroutine
Then try working on your requests/operations with the Ktor, it should work fine.

How to overcome RealmMigrationNeededException error on android app

When I click on launcher icon of my android app, its crashes immediately. I check logcat error, its shows Migration is required due to the following errors: - Property 'PrintJobData.jobPageCount' has been removed.I'm using Realm database and language is kotlin. How to overcome this issue.
private val realmConfig: RealmConfiguration = RealmConfiguration.Builder()
.name("database.realm")
// .deleteRealmIfMigrationNeeded()
.schemaVersion(1)
.build()
private var realm: Realm = Realm.getInstance(realmConfig)
you can delete your realm if a migration is needed:
.deleteRealmIfMigrationNeeded()
or you can write a custom migration for your realm and each change you make to your database MUST be handled in migration.
NOTE: remember after your changes to your database you have to update schemaVersion and also add your custom migration to RealmConfiguration.Builder() like bellow:
val config = RealmConfiguration.Builder()
.name("yourRealmName.realm")
.schemaVersion(2)
.migration(CustomMigration())
.build()
you can learn how to write migration from this and the original document

Android Google Auth Sign In get Id token handleSignInResult:false

I am setting GoogleSignInOptions and Google Api Client like this
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken(getString(R.string.server_client_ID))
.build();
mGoogleApiClient = new GoogleApiClient.Builder(this)
.enableAutoManage(this /* FragmentActivity */, this /* OnConnectionFailedListener */)
.addApi(Auth.GOOGLE_SIGN_IN_API, gso)
.addApi(Plus.API)
.build();
and my google web app client id like this:
1020847812450-xxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com
but always at onActivityResult
if (requestCode == RC_SIGN_IN) {
GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
handleSignInResult(result);
}
is returning false
where am i doing wrong here :S
onStart Section
mGoogleApiClient.connect();
OptionalPendingResult<GoogleSignInResult> opr = Auth.GoogleSignInApi.silentSignIn(mGoogleApiClient);
if (opr.isDone()) {
// If the user's cached credentials are valid, the OptionalPendingResult will be "done"
// and the GoogleSignInResult will be available instantly.
Log.d(TAG, "Got cached sign-in");
// GoogleSignInResult result = opr.get();
// handleSignInResult(result);
} else {
// If the user has not previously signed in on this device or the sign-in has expired,
// this asynchronous branch will attempt to sign in the user silently. Cross-device
// single sign-on will occur in this branch.
opr.setResultCallback(new ResultCallback<GoogleSignInResult>() {
#Override
public void onResult(GoogleSignInResult googleSignInResult) {
handleSignInResult(googleSignInResult);
}
});
}
onStop section
protected void onStop() {
super.onStop();
if (mGoogleApiClient.isConnected()) {
mGoogleApiClient.disconnect();
}
}
onHandleSignInResult
private void handleSignInResult(GoogleSignInResult result) {
Log.e(TAG, "handleSignInResult:" + result.isSuccess());
if (result.isSuccess()) {
// Signed in successfully, show authenticated UI.
final GoogleSignInAccount acct = result.getSignInAccount();
Log.e(TAG, acct.getDisplayName());
}
}
I am also facing the same issue.First remove the current OAuth client ID,after that create one more OAuth client ID.Its worked for me.
Are you getting error 12501? I also had this issue because I was using debug.keystore which comes with the SDK (for some reason unknown to me, it didn't work). I created a new one on my own, got SHA-1 hash from it, entered in Google API console and then it worked.
Be sure you set up signing configs for both debug and release builds with the new keystore.
Follow all the step!!..
Release APK and debug APK has different SHA1 and different API keys for google services. Both of them must be added in Firebase Console -> Project settings. Then download google-services.json from here, add it to project and recompile with release keystore using the option "Build signed APK". That should work
and also read carefully...
https://developer.android.com/studio/publish/app-signing
I believe that you need a call to client.connect(); as per documentation example:
GoogleApiClient client = new GoogleApiClient.Builder(this)
.addApi(Plus.API)
.addScope(Plus.SCOPE_PLUS_LOGIN)
.setAccountName("users.account.name#gmail.com")
.build();
client.connect();
Or is it missing from your question and you are calling connect somwhere else in your code?

Integrating STS with AWSS3TransferManagerUploadRequest and AWSS3TransferManagerDownloadRequest

We are trying to implement AWS Security Token Service in our android and iOS app. At backend we are using below code to generate token:
public class CloudManagementImpl implements CloudManagement{
private static final Logger Log = LoggerFactory.getLogger(CloudManagementImpl.class);
#Override
public CloudConfiguration getCloudProperties() {
CloudConfiguration CloudConfiguration = new CloudConfiguration();
AssumeRoleRequest assumeRoleRequest = new AssumeRoleRequest();
assumeRoleRequest.setRoleArn(JiveGlobals.getProperty(XYZConstant.AWS_ARN_EC2_ROLE_MAP));
assumeRoleRequest.setRoleSessionName(XYZConstant.AWS_ROLE_SESSIONNAME);
assumeRoleRequest.setDurationSeconds(JiveGlobals.getIntProperty(XYZConstant.AWS_CREDENTIALS_LIFETIME, 1800));
AWSSecurityTokenServiceClient stsClient = new AWSSecurityTokenServiceClient();
AssumeRoleResult assumeRoleResult = stsClient.assumeRole(assumeRoleRequest);
if (assumeRoleResult != null) {
Credentials sessionCredentials = assumeRoleResult.getCredentials();
CloudConfiguration.setAwsAccessId(sessionCredentials.getAccessKeyId());
CloudConfiguration.setAwsAccessKey(sessionCredentials.getSecretAccessKey());
CloudConfiguration.setToken(sessionCredentials.getSessionToken());
CloudConfiguration.setAwsMainBucket(JiveGlobals.getProperty(XYZConstant.AWS_MAIN_BUCKET));
} else {
Log.error("Cloud Management :: Propery values not configured ");
}
return CloudConfiguration;
}
}
Generated token is then obtained in iOS and android app through a separate web-service call.
In android we are using below code to consume retrieved token:
public S3Client(String accessKey, String secretKey, String token, String bucketName) {
super();
this.accessKey = accessKey;
this.secretKey = secretKey;
this.bucketName = bucketName;
BasicSessionCredentials basicSessionCredentials = new BasicSessionCredentials(accessKey, secretKey, token);
amazonS3Client = new AmazonS3Client(basicSessionCredentials);
}
Problem is -
We do not have android like API in AWS mobile SDK version 2 for iOS,
using which we can consume the retrieved token, perhaps the best way
to achieve this thing in iOS is through AWSCognitoCredentialsProvider,
but we are not sure.
Please suggest - what is the best way to integrate AWS Security Token Service in iOS.
You need to implement your own credentials provider by conforming to AWSCredentialsProvider. Sounds like you already have a code snippet that retrieves the temporary credentials from your server. That logic should go into your custom credentials provider. You can take a look at the implementation of AWSWebIdentityCredentialsProvider and AWSCognitoCredentialsProvider for how to implement your own credentials provider.