Multiple Firebase Projects in one app with different persistence setup - java

I want to setup 2 Firebase in 1 App, but with difference persistence.
One is enable, and the second is disable.
Please inform me how to set it up.
I take code from link below,
Multiple Firebase projects in one app
but it didn't explain,
how to setup persistence for the second Firebase.
I want to enable persistence for 1st Firebase.
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
And disable persistence for 2nd Firebase.
FirebaseDatabase.getInstance().setPersistenceEnabled(false);
As we see, that getInstance is static method,
how do we know that,
the returned FirebaseDatabase instance,
will belong to 1st or 2nd Firebase.
private void initSecondFirebaseAcct()
{
FirebaseOptions options = new FirebaseOptions.Builder()
.setApplicationId("<your application id>")
.setApiKey("<your api key>")
.setDatabaseUrl("<your DB url that ends in 'firebaseio.com/' ")
.build();
try
{
FirebaseApp.initializeApp(this, options, "<database tag>");
}catch (Exception e){
Log.d("Firebase error", "App already exists");
}
mMySecondApp = FirebaseApp.getInstance("<database tag>");
mSecondDBRef = FirebaseDatabase.getInstance(mMySecondApp).getReference();
}

The way to make sure you are referencing the first or second Firebase app is to provide the specific FirebaseApp instance as a parameter to:
FireDatabase.getInstance(<app instance here>).setPersistenceEnabled().
If you use FirebaseDatabase.getInstance() you will receive the default instance, the first database app. So just provide the second instance as a parameter and you'll be good to go.

Related

Can't write on Realtime Database [duplicate]

I have created a Firebase, and I can write data into Authentication.
But, I could not write data into realtime database.
I have connected to Firebase
I have add Realtime Database
// Import the BoM for the Firebase platform
implementation platform('com.google.firebase:firebase-bom:28.4.1')
// Declare the dependency for the Realtime Database library
// When using the BoM, you don't specify versions in Firebase library dependencies
implementation 'com.google.firebase:firebase-database:20.0.2'
I have set rules of read and write to ture
{
"rules": {
".read": true,
".write": true
}
}
I tried this to write data into Firebase but I get noting
// Write a message to the database
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference myRef = database.getReference("message");
myRef.setValue("Hello, World!");
// Write a message to the database
FirebaseDatabase.getInstance().getReference().child("aaa").child("bbb").setValue("ccc");
FirebaseDatabase.getInstance().getReference().child("aaa").child("bbb").setValue("ccc");
The code for writing looks fine, so I think the problem may be elsewhere.
If you created the Firebase console after you downloaded the google-services.json file, that file will not contain the correct URL, and the SDK may not be able to find your database on the server.
To solve that problem, you can either:
Download an updated google-services.json and use that in your app, or
Provide the database URL in your code with FirebaseDatabase database = FirebaseDatabase.getInstance("database URL here");
My code works this morning, but I did nothing except go to bed. As shown in the picture, the second step has changed. I clicked that Add the Realtime Database SDK to your app button thousands of times, and it was still a button. Surprisingly, it has changed to a checked state.
I did the google-services.json part as #FrankvanPuffelen said yesterday, but it didn't work.
I have restarted the Android Studio a lot of times and didn't work.
Maybe I should try close the computer lid next time.
But now I know that one should have the second step checked rather than keep it as a unchecked button.

Multiple Firebase projects in a single android application

I'm trying to build an android application using Firebase that demands two separate databases (teachers and students) in a single application. I searched for the solution all over the internet but all I got is this solution- Multiple Firebase projects in one app, which seems to be a great solution but I didn't understand.
So, how do I merge two firebase projects in a single application?
Yes, you can follow that guide https://firebase.google.com/docs/projects/multiprojects#java.
Basically, you need to initiate the firebase app providing configuration manually
// [START firebase_options]
// Manually configure Firebase Options. The following fields are REQUIRED:
// - Project ID
// - App ID
// - API Key
FirebaseOptions options1 = new FirebaseOptions.Builder()
.setProjectId("my-firebase-project")
.setApplicationId("1:27992087142:android:ce3b6448250083d1")
.setApiKey("AIzaSyADUe90ULnQDuGShD9W23RDP0xmeDc6Mvw")
// setDatabaseURL(...)
// setStorageBucket(...)
.build();
FirebaseOptions options2 = new FirebaseOptions.Builder()
.setProjectId("my-firebase-project")
.setApplicationId("1:27992087142:android:ce3b6448250083d1")
.setApiKey("AIzaSyADUe90ULnQDuGShD9W23RDP0xmeDc6Mvw")
// setDatabaseURL(...)
// setStorageBucket(...)
.build();
// [END firebase_options]
// [START firebase_secondary]
// Initialize with secondary app
FirebaseApp.initializeApp(this /* Context */, options1, "first");
FirebaseApp.initializeApp(this /* Context */, options2, "secondary");
FirebaseApp first = FirebaseApp.getInstance("first");
FirebaseApp secondary = FirebaseApp.getInstance("secondary");
You can get all required data from google-service.json
Later you can get a database from that FirebaseApp, for example
FirebaseDatabase secondaryDatabase = FirebaseDatabase.getInstance(secondary);
Then you just work with the project like before.
The example you mentioned can be used in the following way.
You can create two main tables in firebase db and then you can do operations by
val reference = FirebaseDatabase.getInstance().getReference()
val teacher = reference.child("teacher")//refers to the teacher table
val student = reference.child("student")//refers to the student table
You don't need to implement the communities solution that is described in that link anymore.
According to this:
Sometimes you need to access different projects using the same APIs - for example, accessing multiple database instances. In most cases there is a central Firebase application object that manages the configuration for all the Firebase APIs. This object is initialized as part of your normal setup. However, when you want to access multiple projects from a single application, you’ll need a distinct Firebase application object to reference each one individually. It’s up to you to initialize these other instances.
you need to first create a Firebase options object to hold the configuration data for the Firebase application, like this:
// Manually configure Firebase Options. The following fields are REQUIRED:
// - Project ID
// - App ID
// - API Key
FirebaseOptions options = new FirebaseOptions.Builder()
.setProjectId("my-firebase-project")
.setApplicationId("1:27992087142:android:ce3b6448250083d1")
.setApiKey("AIzaSyADUe90ULnQDuGShD9W23RDP0xmeDc6Mvw")
// setDatabaseURL(...)
// setStorageBucket(...)
.build();
After you have initialized this options object, you can use it to configure an additional Firebase application instance.
For example, if you have another app instance named "otherApp", you can then do this:
// Initialize with secondary app
FirebaseApp.initializeApp(this /* Context */, options, "otherApp");
// Retrieve secondary FirebaseApp
FirebaseApp secondary = FirebaseApp.getInstance("otherApp");
By this way you connect to an alternative Realtime Database.

Cosmos Db Trigger is not being run when inserting new document

I am using Azure Cosmos DB. I have created a simple trigger in Azure Portal as follows:
var context = getContext();
var request = context.getRequest();
// item to be created in the current operation
var itemToCreate = request.getBody();
itemToCreate["address"] = "test";
// update the item that will be created
request.setBody(itemToCreate);
Unfortunately this trigger is not being triggered when I insert new documents. I have also tried to set the "Trigger Type" to "Post". Am I missing anything?
Great question! I always thought that triggers would run automatically :).
I believe the triggers are not run automatically whenever a document is inserted. What you would need to do is specify the trigger that you want to run when you're creating the document.
What you need to do is register the trigger by passing the trigger name as the request option when sending create document request.
For example, see the code here: https://learn.microsoft.com/en-us/azure/cosmos-db/how-to-use-stored-procedures-triggers-udfs#pre-triggers (copied below as well). Notice the use of PreTriggerInclude in RequestOptions:
dynamic newItem = new
{
category = "Personal",
name = "Groceries",
description = "Pick up strawberries",
isComplete = false
};
Uri containerUri = UriFactory.CreateDocumentCollectionUri("myDatabase", "myContainer");
RequestOptions requestOptions = new RequestOptions { PreTriggerInclude = new List<string> { "trgPreValidateToDoItemTimestamp" } };
await client.CreateDocumentAsync(containerUri, newItem, requestOptions);
Firing triggers automatically in relational databases makes sense since there is schema in
the database, you kind of know what to handle in a trigger logic.
In NoSQL database, since there is no schema, you may end up with a large script to handle all kind of exceptions.
Large script in triggers means higher bills in Cloud. Making triggers automatic can make many customers bill really high specially in IOT solutions.
You can read about Azure Cosmos DB pre/post triggers in my post.
https://h-savran.blogspot.com/2020/03/create-triggers.html
The only way according to the answers from #Guarav Mantri and #Hasan Savaran is to specify the trigger while creating the item through the API. I have managed to do it in Java Azure SDK like that:
RequestOptions options = new RequestOptions();
options.setPreTriggerInclude(Arrays.asList("pre"));
documentClient.createDocument(
collectionLink(),
documentToAdd,
options,
true);
Although I am not happy with this solution because for instance the trigger will not be triggered when creating the item via Portal.

Should I Save token securely in Memory or sqlite? or Please suggest

I started to learn Android few days back and so far I am done with implementing Login Activity, Main Activity which extends abstract Base Activity.
Nav Bar item when clicked opens xml from Fragments.
I have a question about the token that I receive after successful login. This token is being used with each request to get data after successful login. Should I save the token in sqlite database securely or I should make a public property in Main Activity? Main Activity will always remain in memory as this will open fragments.
I can suggest 3 options:
1) you can save the token to the file, something like this:
public static void saveToken(Context ctx, String fileName, Object token) {
if (token == null) {
ctx.deleteFile(fileName);
} else {
ObjectOutputStream out = null;
try {
FileOutputStream fout = ctx.openFileOutput(fileName, 0);
out = new ObjectOutputStream(fout);
out.writeObject(token);
fout.getFD().sync();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (out != null)
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
Make sure object token implements java.io.Serializable interface.
Usage before API level 24:
saveToken(appContext, someFileName, someTokenObject);
Usage with API level 24 and higher:
saveToken(appContext.createDeviceProtectedStorageContext(), someFileName, someTokenObject);
2) Use SQLCipher library for encrypted database.
3) You can encrypt your token using keystore system https://developer.android.com/training/articles/keystore.html
Use SharedPreferences and make sure you are using Context.MODE_PRIVATE this way only your app can access the data. SharedPreferences is a persistent store
e.g.
SharedPreferences prefs = context.getPreferences(Context.MODE_PRIVATE);
prefs.edit().putString("token", token).apply();
token = prefs.getString("token");
Why not to use SQLite:
SQLite is a database and is targeted at tabular data, a single token does not fit this use case.
Why not store in the main activity:
The main activity will not be around for the lifetime of the application install, it can be cleaned up by the OS at any time. It is not a persistent data store.
Should I save the token in sqlite database securely or I should make a public property in Main Activity? Main Activity will always remain in memory as this will open fragments.
The Official Android documentation already answers your question in the section on called "Best practices for security and privacy". It gives the following statement:
If you have access to user data and can avoid storing or transmitting it, don't store or transmit the data
In other words, if you can avoid persisting then don't persist it.
You mentioned "public property" in your question which makes me wonder if the concept of visibility modifiers is not yet clear. The Java public and private modifiers are for controlling access to the members of your class. They have nothing to do with security as per this answer here.
If you do persist the token in memory, as a public field or otherwise, you may reduce your exposure slightly by storing the token in a char[] rather than a String. That also is detailed in this canonical answer.
Finally, if you do have to store the token, the sqlite database is not the correct place to do it. Instead, you should use the provided KeyStore which will make for more difficult extraction of the token in the case that the device is compromised. The link to the documentation above is complete with code examples. If this proves too difficult to use, there are some wrappers around it including Scytale.
1) Store the token value within the base application singleton (where your application must be an instance of BaseApplication)
public class BaseApplication extends Application {
// token
private String token = null;
public String getToken() {return this.token;}
public void setToken(String token) {this.token = token;}
}
With the implementation above you will be able to set and get the token value from any activity/fragment. However the value is not persistent and it will be lost once the application ends.
Remark: If you are using the token for REST api access then you can store the token in the background service instance using a similar solution as above.
2) Use SharedPreferences - this is recommended way in case you want to store the token's value between application's runs.
Please see the answer from #Ryan.
You can use SharedPreferences to store token.it is available over application.
You can store it in Shared Preference as this one is token.
Now coming to the part of Security You can obviously use encryption for the shared preference.
There are already lots of open items available you can use below library for example
https://github.com/ophio/secure-preferences
Regarding keys that are in your java file to encrypt, You need to be sure you are applying proguard before you upload it to playstore.
In that manner now your token is fully secure with shared preferences.
In order to save it in sqlite than by decoding or root access your db file can also be accessed same as preferences. Regarding clear data from setting I think it will delete your sqlite data as well. Not sure about this though.
I hope it will help you out.
Better to use Sqlite or Realm. And store in Application memory and not in external memory. As for data residing in application memory we don't need to worry much about security. Saving in MainActivity is not a good solution, as once application closes, this will get cleared.
Storing in Shared Preference is also an option. But if user clears the cache from setting's this value will also get cleared. Realm Android Reference Link

Parse.com: Get unique number when saving

I use the Parse.com Cloud service in my Android app to sync data between devices.
I use the app mainly offline and use the local data store.
There is one class called Point that has a unique number as identifier I want to display. So when working offline I want to create a Point as draft (with a draft text as number) and when synchronizing I want it to get the real number that is unique over all the devices.
How would I set the number when saving? I was thinking about adding a WebHook in the cloud when saving the Point and giving it a unique number and then in my app use
newPoint.saveEventually(new SaveCallback() {
public void done(ParseException e) {
//query for the number
}
});
to query the point from the cloud to get the number after it has been saved. But this seems kind of too complicated for such a simple requirement. And I am not sure if the SaveCallback() is always triggered when saving it.
I would recommend using an afterSave trigger on the Point class to set the unique identifier when the object is newly created. Then, as you've mentioned, you'll need to fetch the value before displaying it.
Here's what the cloud code could look like:
// Assign the Point a unique identifier on creation
Parse.Cloud.afterSave("Point", function(request) {
// Check if the Point is new
if (!(request.object.existed())) {
// Get the unique identifier
var uniqueIdentifier = ...
// Set the unique identifier
request.object.set('uniqueIdentifier', uniqueIdentifier);
}
});
One important bit of information to keep in mind about using saveEventually with SaveCallback() is:
The callback will only be called if the operation completes within the
current app lifecycle. If the app is closed, the callback can't be
called, even if the save eventually is completed.
Source: Hector Ramos
If the unique identifier should be immediately displayed in the app or if the callback needs to be handled consistently, it would probably be best to use saveInBackground rather than saveEventually.
Another option would be to dynamically change the callback depending on network availability and/or offline settings. For example, if the offline mode is used anytime when the cell signal or wifi is unavailable, then network reachability could be used to check for a network and then use saveInBackground or saveEventually as appropriate.
Update
OP ended up using this code:
Parse.Cloud.beforeSave("Point", function(request, response) {
if (!(request.object.existed())) {
var query = new Parse.Query("Point");
query.addDescending("uniqueIdentifier");
query.first({
success: function(result) {
var maxId = result.get("uniqueIdentifier");
request.object.set("uniqueIdentifier", maxId + 1);
},
error: function() {
}
});
}
response.success();
});

Categories