You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
So this will be a little long since I think I have to give some context. I'm writing this for posterity and for anyone who suffers the same problem I will describe.
Since my firsts steps with LoopBack, I experienced intermittent issues with user persistence in my app. The problem would just not make sense: the user could log in correctly, but after some time, the user would have to log in again, although I could confirm that the token was still saved in the shared preference of the SDK.
Worse, I could not reproduce the problem. No idea where to go from there, and why this could happen. After I had reviewed my code several times, I began to suspect that the SDK itself was causing the issue, but again, I wasn't able to even start debugging the problem (not reproducible, remember?).
The application being a launcher type app, it has a very long lifecycle, increasing the difficulty of isolating the problem.
So, thinking it was an isolated problem that only some users had, I pursued developing the app, until, at some point, I had to write some code that refreshed the user object to check for newly added props added server-side. It was working perfectly on my emulator and my phone. The day following the release, we had multiple user reports that the application was non-functional, and I had to revert my changes in a hurry.
There. I finally had something to work with. I began suspecting the differences between the debug and release builds, so I developed a rapid proof-of-concept app, and I was able to reproduce the issue. Hurray!
I was then able to finally pinpoint the issue down to these lines in UserRepository, where an AccessToken model, is created from the JSON response from the API. The issue is that the createObject method ultimately uses BeanUtil, to set the properties (here the userId) by using reflexion and calling the appropriate methods for each value in the JSON response, here that would be AccessToken.setUserId().
However, and that's why I wasn't able to reproduce the issue, I'm using proguard to obfuscate the release code that's being published on Google Play. This results in methods and attributes being renamed to very basic names, like a, b, etc. So now BeanUtil is looking for A.setUserId(), whereas the actual method has been obfuscated to something like A.a(), and it fails silently. (expected behaviour in a way, because you can't throw an error for every JSON property that doesn't have its corresponding setter)
All that to say, that there is NEVER, ever, some indication about such behaviour, nor any documentation about how to configure Proguard if we use the SDK.
Finally, the solution was to add the following lines to your proguard-rules.pro file:
-keepclassmembers class * extends com.strongloop.android.loopback.Model {
public <methods>;
}
This literally says: "Do not obfuscate methods and members that are from classes extending Model"
This problem should really be documented somewhere since I believe (I may be mistaken about this) that Proguard is widely used in production use, and that every library should be aware of issues that code obfuscating could cause to their codebase.
Sorry about the excessively long issue, but I felt like I had to speak my mind about that, no hard feelings, happy to report back to the open source community, so that no one spends an other day debugging that!
The text was updated successfully, but these errors were encountered:
@saveman71 Hello, thank you for reporting this issue and providing such detailed information! I agree we should at least capture this in our documentation. @crandmck could you PTAL?
It makes me wonder, how do other JSON serializers cope with obfuscation? Would it make sense to switch our implementation to use a 3rd party library instead of maintaining our own BeanUtil?
So this will be a little long since I think I have to give some context. I'm writing this for posterity and for anyone who suffers the same problem I will describe.
Since my firsts steps with LoopBack, I experienced intermittent issues with user persistence in my app. The problem would just not make sense: the user could log in correctly, but after some time, the user would have to log in again, although I could confirm that the token was still saved in the shared preference of the SDK.
Worse, I could not reproduce the problem. No idea where to go from there, and why this could happen. After I had reviewed my code several times, I began to suspect that the SDK itself was causing the issue, but again, I wasn't able to even start debugging the problem (not reproducible, remember?).
The application being a launcher type app, it has a very long lifecycle, increasing the difficulty of isolating the problem.
So, thinking it was an isolated problem that only some users had, I pursued developing the app, until, at some point, I had to write some code that refreshed the user object to check for newly added props added server-side. It was working perfectly on my emulator and my phone. The day following the release, we had multiple user reports that the application was non-functional, and I had to revert my changes in a hurry.
There. I finally had something to work with. I began suspecting the differences between the debug and release builds, so I developed a rapid proof-of-concept app, and I was able to reproduce the issue. Hurray!
Here it is: saveman71/strongloop-sdk-android-proguard-poc
I was then able to finally pinpoint the issue down to these lines in
UserRepository
, where anAccessToken
model, is created from the JSON response from the API. The issue is that thecreateObject
method ultimately usesBeanUtil
, to set the properties (here theuserId
) by using reflexion and calling the appropriate methods for each value in the JSON response, here that would beAccessToken.setUserId()
.However, and that's why I wasn't able to reproduce the issue, I'm using proguard to obfuscate the release code that's being published on Google Play. This results in methods and attributes being renamed to very basic names, like
a
,b
, etc. So nowBeanUtil
is looking forA.setUserId()
, whereas the actual method has been obfuscated to something likeA.a()
, and it fails silently. (expected behaviour in a way, because you can't throw an error for every JSON property that doesn't have its corresponding setter)All that to say, that there is NEVER, ever, some indication about such behaviour, nor any documentation about how to configure Proguard if we use the SDK.
Finally, the solution was to add the following lines to your
proguard-rules.pro
file:This literally says: "Do not obfuscate methods and members that are from classes extending
Model
"This problem should really be documented somewhere since I believe (I may be mistaken about this) that Proguard is widely used in production use, and that every library should be aware of issues that code obfuscating could cause to their codebase.
Sorry about the excessively long issue, but I felt like I had to speak my mind about that, no hard feelings, happy to report back to the open source community, so that no one spends an other day debugging that!
The text was updated successfully, but these errors were encountered: