I wanted to user firestore in my unity proyect, so I did as in the documentation. Notice that I also do db = FirebaseFirestore.DefaultInstance;.
I put the firebase starting code in a trial monobehviour in of my scene, in which I wanted to make some database query trials.
Firebase.FirebaseApp app;
void Start() {
Firebase.FirebaseApp.CheckAndFixDependenciesAsync().ContinueWith(task => {
var dependencyStatus = task.Result;
if (dependencyStatus == Firebase.DependencyStatus.Available) {
// Create and hold a reference to your FirebaseApp,
// where app is a Firebase.FirebaseApp property of your application class.
app= Firebase.FirebaseApp.DefaultInstance;
Debug.LogError("FirebaseApp succesfully created");
// Set a flag here to indicate whether Firebase is ready to use by your app.
} else {
UnityEngine.Debug.LogError(System.String.Format(
"Could not resolve all Firebase dependencies: {0}", dependencyStatus));
// Firebase Unity SDK is not safe to use here.
}
});
db = FirebaseFirestore.DefaultInstance;
}
Every time I stopped my app and re-played in the editor, unity freezed, and I had to kill the process and restart unity.
Since I commented out the: app= Firebase.FirebaseApp.DefaultInstance;
to: //app= Firebase.FirebaseApp.DefaultInstance; as I only wanted to use the database, everything is going fine.
Am I doing something wrong? Does it make sense that due to some mistake unity hangs after re-play (first play works).
On the other hand I dont understand why in the docs the code advices to store the FirebaseApp in a variable if the FirebaseApp class has got an static instance getter: public static FirebaseApp DefaultInstance { get; }
Thanks for any comment.
Related
Realms.Exception.RealmInvalidTransactionException: Cannot modify managed objects outside of a write transaction
I was using Ream .Net SDK 10.13 and recently updated it to 10.19.0. After, the update I am frequently getting the above error.
Here is an example of how I am using it in my Xamarin Forms project
public class TestClass: RealmObject
{
//Class properties are defined
// as per the realm docs, proper attributes
//are added for Kets and mapping
}
Now in some class/view models, where I have an instance of the TestClass injected through the constructor
public async Task<SomeUserDefinedType> SomeMethod(TestClass item){
var realm = Realms.Realm.GetInstance();
await realm.WriteAsync(async()=>{
// setting property of the TestClass
item.SomeProperty = "Some Value";
});
return <Instance of SomeUserDefinedType>;
}
The above method call gives an exception. Above code is modified as per the new version.
The below code was as per the older version which was working fine but it started giving the same exception after the update
public async Task<SomeUserDefinedType> SomeMethod(TestClass item){
await item.WriteAsync(async i =>{
// setting property of the TestClass
i.SomeProperty = "Some Value";
});
return <Instance of SomeUserDefinedType>;
}
I tried many ways to resolve this issue but none is working.
Any Suggestions/Help will be highly appreciated.
Unity editor version: 2020.3.20f1
Firebase Unity SDK version: firebase_unity_sdk_8.6.2
Additional SDKs: Admob SDK
Platform Unity editor on Windows
Platform targeting: Android
Scripting Runtime: IL2CPP
API Compability Level: .NET 4.x
Issue
Crashlytics is stuck like this, but the analytics is getting data.
I'm already installed Crashlytics SDK on my project and added configurations like on the document but skip part 4: that symbol thing.
( https://firebase.google.com/docs/crashlytics/get-started?platform=unity ) to my script
so my script becomes like this:
public static FirebaseManager Instance;
private FirebaseApp app;
private void Awake()
{
Instance = this;
}
private void Start()
{
InitFB();
}
private void InitFB()
{
// Initialize Firebase
FirebaseApp.CheckAndFixDependenciesAsync().ContinueWithOnMainThread(task =>
{
var dependencyStatus = task.Result;
if (dependencyStatus == DependencyStatus.Available)
{
// Create and hold a reference to your FirebaseApp,
// where app is a Firebase.FirebaseApp property of your application class.
// Crashlytics will use the DefaultInstance, as well;
// this ensures that Crashlytics is initialized.
app = FirebaseApp.DefaultInstance;
FirebaseApp.LogLevel = LogLevel.Debug;
Debug.Log(dependencyStatus);
// Set a flag here for indicating that your project is ready to use Firebase.
}
else
{
Debug.LogError(System.String.Format(
"Could not resolve all Firebase dependencies: {0}", dependencyStatus));
// Firebase Unity SDK is not safe to use here.
}
});
}
then implement for tests like the doc ( https://firebase.google.com/docs/crashlytics/test-implementation?platform=unity )
Test script
int updatesBeforeException;
// Start is called before the first frame update
void Start()
{
updatesBeforeException = 0;
}
private void Update()
{
// Call the exception-throwing method here so that it's run
// every frame update
throwExceptionEvery60Updates();
}
// A method that tests your Crashlytics implementation by throwing an
// exception every 60 frame updates. You should see non-fatal errors in the
// Firebase console a few minutes after running your app with this method.
void throwExceptionEvery60Updates()
{
if (updatesBeforeException > 0)
{
updatesBeforeException--;
}
else
{
// Set the counter to 60 updates
updatesBeforeException = 60;
// Throw an exception to test your Crashlytics implementation
throw new System.Exception("test exception please ignore");
}
}
When I run the app on the editor, initialize return available then I test crash it work
am I doing wrong here?
I wanted to use Firebase in my Unity game so one of the steps was to add the following code, but the place into which the code should be added wasn't specified. Any help?
Firebase.FirebaseApp.CheckAndFixDependenciesAsync().ContinueWith(task => {
var dependencyStatus = task.Result;
if (dependencyStatus == Firebase.DependencyStatus.Available) {
// Create and hold a reference to your FirebaseApp,
// where app is a Firebase.FirebaseApp property of your application class.
app = Firebase.FirebaseApp.DefaultInstance;
// Set a flag here to indicate whether Firebase is ready to use by your app.
} else {
UnityEngine.Debug.LogError(System.String.Format(
"Could not resolve all Firebase dependencies: {0}", dependencyStatus));
// Firebase Unity SDK is not safe to use here.
}
});
(This is the link to the instructions on Firebase)
https://firebase.google.com/docs/unity/setup?authuser=0#confirm-google-play-version
The best answer I can give is "before you do anything else" in Unity.
In a normal application, you'd have something like a main api entry point (application:didFinishLaunchingWithOptions in iOS, Activity.onCreate in Android, or literally void main(int,char**) in a typical C/C++ desktop application). But in Unity, you don't have any sort of "run this before everything else" logic. Whichever scene is first is up to you and subject to change, and scripts execute roughly in parallel (in an order that's best considered random but technically can be ordered).
Here are the patterns I've either used or have thought about using and a few associated pros and cons:
[Recommended for beginners and small projects] In my videos, I typically recommend having a "loading" or "setup" scene. In that scene I place a FirebaseInit script that will initialize Firebase and raise an event when it's done. I can then either collect a bunch of initialization functionality (say downloading asset bundles or doing some initial setup processing) or just jump immediately into my main scene. Most of the time this will resolve to a no-op (on Android play services is up to date), so you can even shove it in the main menu if you're careful:
using System;
using Firebase;
using Firebase.Extensions;
using UnityEngine;
using UnityEngine.Events;
public class FirebaseInit : MonoBehaviour
{
public UnityEvent OnInitialized = new UnityEvent();
public InitializationFailedEvent OnInitializationFailed = new InitializationFailedEvent();
void Start()
{
FirebaseApp.CheckAndFixDependenciesAsync().ContinueWithOnMainThread(task =>
{
if (task.Exception != null)
{
OnInitializationFailed.Invoke(task.Exception);
}
else
{
OnInitialized.Invoke();
}
});
}
[Serializable]
public class InitializationFailedEvent : UnityEvent<Exception>
{
}
}
I'm not a big proponent of dependency injection (as in I typically don't use DI frameworks, but I do tend to use [SerializedField]s as a pseudo-DI system), so I don't have a good example to share. You can use ZenJect to create and inject the Firebase singletons to anything that needs them. The biggest issue you run into is that you have to await the dependencies to be initialized, which is possible but I just haven't gone through the steps of doing it in a sample project. The benefit is that you only need to express "I depend on Firebase", and ZenJect will take care of the rest (just avoid the DefaultInstance functions in this case).
In more complex projects, I'll tend to wrap Firebase in a Coroutine (or an async task, but I prefer coroutines in Unity). So I'll have a Coroutine that will wait for check and fix dependencies to complete and return an instance of Realtime Database when it finishes (and intelligent logic to skip the waiting if not necessary). Again you have to avoid DefaultInstance outside of your management script, and every use of Firebase becomes a coroutine, but you can be sure that you always await on construction. Here is one example focusing on Realtime Database (I'm stripping unnecessary code to make it fit in a SO answer), and I'll reiterate that this is a lot of overhead for a small project:
public class FirebaseBehaviour : MonoBehaviour
{
private IEnumerator _setupFirebase;
private DatabaseReference _databaseReference;
void Awake()
{
// everything depends on firebase being setup. Do this first.
_setupFirebase = SetupFirebase();
StartCoroutine(_setupFirebase);
}
private IEnumerator SetupFirebase()
{
// we need to fix dependencies on Android
if (Application.platform == RuntimePlatform.Android && !Application.isEditor)
{
Debug.Log("Checking dependencies on Android");
var checkDependencies = new TaskYieldInstruction<DependencyStatus>(FirebaseApp.CheckDependenciesAsync());
yield return checkDependencies;
Debug.Log($"Check Dependencies: {checkDependencies.Result}");
}
_databaseReference = FirebaseDatabase.DefaultInstance.RootReference;
}
/// <summary>
/// Safely gets a database reference at the given path
/// </summary>
/// <param name="path">The path at which to get a reference</param>
/// <returns>A yield instruction that can be yielded in a coroutine</returns>
public GetDatabaseReferenceYieldInstruction GetDatabaseReference(string path)
{
return new GetDatabaseReferenceYieldInstruction(path, _setupFirebase);
}
/// <summary>
/// Asynchronously gets a database reference at the given path after a predicate executes
/// </summary>
public class GetDatabaseReferenceYieldInstruction : IEnumerator
{
private IEnumerator _predicate;
private readonly string _path;
public DatabaseReference Root { get; private set; }
public GetDatabaseReferenceYieldInstruction(string path, IEnumerator predicate)
{
_path = path;
_predicate = predicate;
}
public bool MoveNext()
{
if (_predicate != null)
{
if (_predicate.MoveNext())
{
return true;
}
_predicate = null;
// TODO: this is a cross cutting concern to inject
Root = FirebaseDatabase.DefaultInstance.RootReference.Child(_path);
}
return false;
}
public void Reset()
{
}
public object Current => Root;
}
}
Which you can use like this:
[SerializeField] private FirebaseSingleton _firebaseSingleton;
public void Awake()
{
_firebase = _firebaseSingleton.Instance;
_getDatabase = _firebase.GetDatabaseReference(DatabaseName);
}
private IEnumerator RegisterForEvents()
{
yield return _getDatabase;
_getPigDatabase.Root.ValueChanged += HandlePigValuesChanged;
}
With Unity's new DOTS system, I've been flirting with the idea of moving Unity's initialization into the OnCreate function for a system. Because you have a clean entrypoint, you'd be able to block Firebase functionality until it comes online, and you could control Firebase by injecting specific entities into the world with custom Firebase-specific components on it. I don't have a good example yet, although it's on my project backlog.
I am trying to use the Firebase package with the below line of code.
I really want to know what this line of code actually does?
The official documentation didn't help me much. Can someone explain me, please?
You have to use it, in this way:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
https://flutter.dev/docs/resources/architectural-overview#architectural-layers
The above image is the architecture layers of Flutter, the WidgetFlutterBinding is used to interact with the Flutter engine. Firebase.initializeApp() needs to call native code to initialize Firebase, and since the plugin needs to use platform channels to call the native code, which is done asynchronously therefore you have to call ensureInitialized() to make sure that you have an instance of the WidgetsBinding.
From the docs:
Returns an instance of the WidgetsBinding, creating and initializing it if necessary. If one is created, it will be a WidgetsFlutterBinding. If one was previously initialized, then it will at least implement WidgetsBinding.
You only need to call this method if you need the binding to be initialized before calling runApp.
From the source code:
#override
Future<FirebaseAppPlatform> initializeApp(
{String name, FirebaseOptions options}) async {
if (name == defaultFirebaseAppName) {
throw noDefaultAppInitialization();
}
// Ensure that core has been initialized on the first usage of
// initializeApp
if (!isCoreInitialized) {
await _initializeCore();
}
// If no name is provided, attempt to get the default Firebase app instance.
// If no instance is available, the user has not set up Firebase correctly for
// their platform.
if (name == null) {
MethodChannelFirebaseApp defaultApp =
appInstances[defaultFirebaseAppName];
if (defaultApp == null) {
throw coreNotInitialized();
}
return appInstances[defaultFirebaseAppName];
}
assert(options != null,
"FirebaseOptions cannot be null when creating a secondary Firebase app.");
// Check whether the app has already been initialized
if (appInstances.containsKey(name)) {
throw duplicateApp(name);
}
_initializeFirebaseAppFromMap(await channel.invokeMapMethod(
'Firebase#initializeApp',
<String, dynamic>{'appName': name, 'options': options.asMap},
));
return appInstances[name];
}
The invokeMapMethod will invoke a method on the above channel with the specified arguments, which will then call the initializeApp() method in the native code,
https://github.com/FirebaseExtended/flutterfire/blob/master/packages/firebase_core/firebase_core/android/src/main/java/io/flutter/plugins/firebase/core/FlutterFirebaseCorePlugin.java#L227
There are also different ways to initialize Firebase, which you can check here:
No Firebase App '[DEFAULT]' has been created - call Firebase.initializeApp() in Flutter and Firebase
In the other ways we do not call WidgetsFlutterBinding.ensureInitialized() since the runApp() function calls it internally:
void runApp(Widget app) {
WidgetsFlutterBinding.ensureInitialized()
..scheduleAttachRootWidget(app)
..scheduleWarmUpFrame();
}
https://github.com/flutter/flutter/blob/bbfbf1770c/packages/flutter/lib/src/widgets/binding.dart#L1012
A simple answer is that if Flutter needs to call native code before calling runApp
WidgetsFlutterBinding.ensureInitialized();
makes sure that you have an instance of the WidgetsBinding, which is required to use platform channels to call the native code.
You only need to call this method if you need the binding to be
initialized before calling runApp.
A simple answer, you need to use this line, if your main function uses async keyword because you use await statement inside it.
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
SharedPreferences prefs = await SharedPreferences.getInstance(); // just an example
}
I'm quite new to the Microservice world and particularly vertX. I want my verticle to start anyway even there is no database connection available (e.g. database URL missing in configuration). I already managed to do this and my verticle is starting.
The issue now is that I want my verticle to notice when the database connection is available again and connect to it. How can I do this ?
I thought about creating another Verticle "DatabaseVerticle.java" which would send the current DB config on the event bus and my initial verticle would consume this message and check whether the config info is consistent (reply with success) or still missing some data (reply with fail and make the DatabaseVerticle check again).
This might work (and might not) but does not seem to be the optimal solution for me.
I'd be very glad if someone could suggest a better solution. Thank you !
For your use case, I'd recommend to use the vertx-config. In particular, have a look at the Listening to configuration changes section of the Vert.x Config documentation.
You could create a config retriever and set a handler for changes:
ConfigRetrieverOptions options = new ConfigRetrieverOptions()
.setScanPeriod(2000)
.addStore(myConfigStore);
ConfigRetriever retriever = ConfigRetriever.create(vertx, options);
retriever.getConfig(json -> {
// If DB config available, start the DB client
// Otherwise set a "dbStarted" variable to false
});
retriever.listen(change -> {
// If "dbStarted" is still set to false
// Check the config and start the DB client if possible
// Set "dbStarted" to true when done
});
The ideal way would be some other service telling your service about database connection. Either through event bus or HTTP, what you can do is when someone tries to access your database when connection is not made just try to make some DB call and handle the exception, return a boolean as false. Now when you get a message on event bus, consume it and save it in some config pojo. Now when someone tries to access your database, look for config and if available make a connection.
Your consumer:
public void start(){
EventBus eb = vertx.eventBus();
eb.consumer("database", message -> {
config.setConfig(message.body());
});
}
Your db client(Mongo for this eg):
public class MongoService{
private MongoClient client;
public boolean isAvailable = false;
MongoService(Vertx vertx){
if(config().getString("connection")){
client = MongoClient.createShared(vertx, config().getString("connection"));
isAvailable = true;
}
}
}
Not everything in Vertx should be solved by another verticle.
In this case, you can use .periodic()
http://vertx.io/docs/vertx-core/java/#_don_t_call_us_we_ll_call_you
I assume you have some function that checks the DB for the first time.
Let's call it checkDB()
class PeriodicVerticle extends AbstractVerticle {
private Long timerId;
#Override
public void start() {
System.out.println("Started");
// Should be called each time DB goes offline
final Long timerId = this.vertx.setPeriodic(1000, (l) -> {
final boolean result = checkDB();
// Set some variable telling verticle that DB is back online
if (result) {
cancelTimer();
}
});
setTimerId(timerId);
}
private void cancelTimer() {
System.out.println("Cancelling");
getVertx().cancelTimer(this.timerId);
}
private void setTimerId(final Long timerId) {
this.timerId = timerId;
}
}
Here I play a bit with timerId, since we cannot pass it to cancelTimer() right away. But otherwise, it's quite simple.