Firebase writes different files if app is debug or release version - firebase

I just found out something very odd with Firebase and I would like to know if it is me that's doing something wrong or if there is a solution to this problem.
Basically, this is what it has always written when I was developing the app (and it's precisely what I was expecting):
nscoachtools#gmail¸com
maxMatches: 60
maxPlayers: 500
maxTeams: 30
userId: "SnMuRZEVqyN***...***hv2"
userMail: "nscoachtools#gmail.com"
userName: "Nicola Salvaro"
userPicture: "https://lh4.googleusercontent.com/-L7lSPz0VJ9A/..."
userToken: -1
and this is what it writes after I built the app in release mode:
nsalvaro77#gmail¸com
a: "Nicola Salvaro"
b: "ESjqwuh***...***wg1"
c: "nsalvaro77#gmail.com"
d: "https://lh4.googleusercontent.com/-2kwSEmLEN1c/..."
e: -2
f: 30
g: 500
h: 60
userToken: 1499775285255
Every "title" has been replaced with a letter. And "e: " was supposed to be "userToken: " then, when I tried to update it, it wrote it with the proper string but not on top of the original value... just wrote a new one. Then, when I try to read the full user, it gets the value of "e: ", not the "userToken: " one.
Did I do something wrong?

In release mode your Android app is being minified by Proguard. This process strips unused methods and makes other method names shorter.
As a consequence, your POJO classes (the classes your read from/write to Firebase) are getting new method names and Firebase reflectively uses those method names to determine the properties in the JSON.
The solution is to tell Proguard to not modify the method names of your POJOs.
More on that:
The oldest Q&A on how to do this is: What ProGuard configuration do I need for Firebase on Android?. But that one is from Firebase 2.x, while many of these are auto-included in Firebase 9 and up.
You can also potentially mark the classes with #Keep, see Firebase No properties to serialize found on class.
More interesting Q&A on this topic: https://stackoverflow.com/search?q=%5Bfirebase-database%5D+proguard+release

Related

How do I make a query equalto with a long value?

I tried to make a query from real time database using equalTo().
database.getReference(verifiedProductsDb.dbPartVerifiedProducts).order By Child(verifiedProductsDb.barcode).equalTo(b.toLong()).get().addOnCompleteListener {
but android studio gives out:
None of the following functions can be called with the argument supplied.
equalTo(Boolean) defined in com.google.firebase.database.Query
equalTo(Double) defined in com.google.firebase.database.Query
equal To(String?) defined in com.google.firebase.database.Query
Despite the fact that using setValue, long values are written to the same database quite successfully and without problems.
The Realtime Database API on Android only has support for Double number types. The underlying wire protocol and database will interpret the long numbers correctly though, so you should be able to just do:
database.getReference("VerifiedProducts")
.orderByChild("barcode")
.equalTo(b.toLong().toDouble()) // 👈
.get().addOnCompleteListener {
...

Evernote IOS SDK fetchResourceByHashWith throws exception

Working with Evernote IOS SDK 3.0
I would like to retrieve a specific resource from note using
fetchResourceByHashWith
This is how I am using it. Just for this example, to be 100% sure about the hash being correct I first download the note with a single resource using fetchNote and then request this resource using its unique hash using fetchResourceByHashWith (hash looks correct when I print it)
ENSession.shared.primaryNoteStore()?.fetchNote(withGuid: guid, includingContent: true, resourceOptions: ENResourceFetchOption.includeData, completion: { note, error in
if error != nil {
print(error)
seal.reject(error!)
} else {
let hash = note?.resources[0].data.bodyHash
ENSession.shared.primaryNoteStore()?.fetchResourceByHashWith(guid: guid, contentHash: hash, options: ENResourceFetchOption.includeData, completion: { res, error in
if error != nil {
print(error)
seal.reject(error!)
} else {
print("works")
seal.fulfill(res!)
}})
}
})
Call to fetchResourceByHashWith fails with
Optional(Error Domain=ENErrorDomain Code=0 "Unknown error" UserInfo={EDAMErrorCode=0, NSLocalizedDescription=Unknown error})
The equivalent setup works on Android SDK.
Everything else works so far in IOS SDK (chunkSync, auth, getting notebooks etc.. so this is not an issue with auth tokens)
would be great to know if this is an sdk bug or I am still doing something wrong.
Thanks
This is a bug in the SDK's "EDAM" Thrift client stub code. First the analysis and then your workarounds.
Evernote's underlying API transport uses a Thrift protocol with a documented schema. The SDK framework includes a layer of autogenerated stub code that is supposed to marshal input and output params correctly for each request and response. You are invoking the underlying getResourceByHash API method on the note store, which is defined per the docs to accept a string type for the contentHash argument. But it turns out the client is sending the hash value as a purely binary field. The service is failing to parse the request, so you're seeing a generic error on the client. This could reflect evolution in the API definition, but more likely this has always been broken in the iOS SDK (getResourceByHash probably doesn't see a lot of usage). If you dig into the more recent Python version of the SDK, or indeed also the Java/Android version, you can see a different pattern for this method: it says it's going to write a string-type field, and then actually emits a binary one. Weirdly, this works. And if you hack up the iOS SDK to do the same thing, it will work, too.
Workarounds:
Best advice is to report the bug and just avoid this method on the note store. You can get resource data in different ways: First of all, you actually got all the data you needed in the response to your fetchNote call, i.e. let resourceData = note?.resources[0].data.body and you're good! You can also pull individual resources by their own guid (not their hash), using fetchResource (use note?.resources[0].guid as the param). Of course, you may really want to use the access-by-hash pattern. In that case...
You can hack in the correct protocol behavior. In the SDK files, which you'll need to build as part of your project, find the ObjC file called ENTProtocol.m. Find the method +sendMessage:toProtocol:withArguments.
It has one line like this:
[outProtocol writeFieldBeginWithName:field.name type:field.type fieldID:field.index];
Replace that line with:
[outProtocol writeFieldBeginWithName:field.name type:(field.type == TType_BINARY ? TType_STRING : field.type) fieldID:field.index];
Rebuild the project and you should find that your code snippet works as expected. This is a massive hack however and although I don't think any other note store methods will be impacted adversely by it, it's possible that other internal user store or other calls will suddenly start acting funny. Also you'd have to maintain the hack through updates. Probably better to report the bug and don't use the method until Evernote publishes a proper fix.

When are writeFields specified in Firestore requests and what replaces them?

The simulator now displays an error message trying to access request.writeFields.
Before that writeFields in Firestore Security Rules did just not work in real requests.
The message states the following:
The simulator only simulates client SDK calls; request.writeFields is always null for these simulations
Does this mean that writeFields are only specified in HTTP requests?
The documentation only states this:
writeFields: List of fields being written in a write request.
A problem that arises from this
I am searching for something that replaces this property because it is "always null".
request.resource.data in update also contains fields that are not in the requests, but already in the document to my knowledge.
Example
// Existing document:
document:
- name: "Peter"
- age: 52
- profession: "Baker"
// Update call:
document:
- age: 53
// request.resource.data in allow update contains the following:
document:
- name: "Peter"
- age: 53
- profession: "Baker"
But I only want age.
EDIT Mar 4, 2020: Map.diff() replaces writeFields functionality
The Map.diff() function gives the difference between two maps:
https://firebase.google.com/docs/reference/rules/rules.Map#diff
To use it in rules:
// Returns a MapDiff object
map1.diff(map2)
A MapDiff object has the following methods
addedKeys() // a set of strings of keys that are in after but not before
removedKeys() // a set of strings of keys that are in before but not after
changedKeys() // a set of strings of keys that are in both maps but have different values
affectedKeys() // a set of strings that's the union of addedKeys() + removedKeys() + updatedKeys()
unchangedKeys() // a set of strings of keys that are in both maps and have the same value in both
For example:
// This rule only allows updates where "a" is the only field affected
request.resource.data.diff(resource.data).affectedKeys().hasOnly(["a"])
EDIT Oct 4, 2018: writeFields is no longer supported by Firestore and its functionality will eventually be removed.
writeFields is still valid, as you can see from the linked documentation. What the error message in the simulator is telling you is that it's unable to simulate writeFields, as it only works with requests coming from client SDKs. The simulator itself seems to be incapable of simulating requests exactly as required in order for writeFields to be tested. So, if you write rules that use writeFields, you'll have to test them by using a client SDK to perform the read or write that would trigger the rule.

Why does the url property key in Firebase snapshot keep changing?

I have not seen any discussion or awareness so far that Firebase does in fact make available a unique identifier--in fact the full URL--to each specific data record via their "snapshot" which they return, i.e. the wrapper around the data record (accessed via snapshot.val()). By doing a basic property examination of the snapshot I discovered that the unique URL is available (see examples below). However, it seems that, for some reason, Firebase keeps changing the name of the key every few days, causing my application to break. I have to go in and re-discover the new URL property key and change it so that it will work again.
Here are three examples of how I have seen the key change so far. Each value is the same, but the key keeps changing over time (i.e.: "Wb", "Xb", "bc").:
getMemberBySnapshot - snapshot has prop Wb with value https://prototype1.firebaseio.com/users/-IwohKfw1l5F3gFqyJJ5
getMemberBySnapshot - snapshot has prop Xb with value https://prototype1.firebaseio.com/users/-IwohKfw1l5F3gFqyJJ5
getMemberBySnapshot - snapshot has prop bc with value https://prototype1.firebaseio.com/users/-IwohKfw1l5F3gFqyJJ5
I have read Firebase's suggestions that developers should use an email address if they want a unique key (what if my model does not use an email field? What if a user wants to change their email?), or Firebase suggests altenatively to retrieve all existing records and then search through them on the client. Neither of these solutions are satisfying. But I'm seeing that they do provide the unique URL to each data record in the 'snapshot'. Why do they not provide a stabilized key so that a developer can call it consistently???
Firebase.js is a compiled script. The names of internal variables will change every time we compile it and release a new version, so you should definitely not be relying on any properties that are not documented on our website.
For your specific case, you should be using:
snapshot.ref().toString()
in order to get the URL.

signalR message structure flags clarification?

I've read here about the structure of signalR's response message :
for example
For PersistentConnection
{"C":"B,2CE|K,C|L,2|M,0|I,0|J,0","M":["foo"]}
Where
Persistent Response:
C - cursor
M - Messages
T - Timeout (only if true) value is 1
D - Disconnect (only if true) value is 1
R - All Groups (Client groups should be reset to match this list exactly)
G - Groups added
g - Groups removed
Question #1
What's wrong with sending only the message part ? why do i need all the "C" information ? The client only needs the message. A message number #N is not dependent with message number #N-1 (AFAIK) -- so I dont see the reason for this "C" section. ( and I assume Im wrong by missing something here).
Question #2
Even so , how can I understand what the tokens means ? I didn't see in the manual the "K,L,I,J,2CE" tokens.
Where / How can I understand what they are saying ? What if I don't want the server to send that info but only the message ?
Open Source has an often over looked feature. You can simply download the source and take a look around. By simply searching in the source for the string "R" I was able to find some of the information you are looking for.
Answer #2:
These shorthand property names directly map to the JsonSerialization of objects in SignalR.
HubResponse
S - State
R - Result
I - Id
E - Error
T - StackTrace
PersistantResponse
L - LongPollDelay
D - Disconnect
T - TimedOut
G - GroupsToken
Some of the others are not found in the current code base, and since the issue your referring to is 7 months old I would guess they have been refactored out.
Answer #1:
The metadata is important to how SignalR operates. The double edged sword of frameworks is that we offload the domain or what it solves to the framework and its creators, and we implicitly agree to let them be the domain expert. Sometimes that makes it a bit of a black box to use, if you want to see what each of these properties are actually used for download the source and follow the code. If for some performance reason you feel the need to trim out some of the code around what you determine to be extraneous fork the code and give it a shot.

Resources