How to Programmatically Upgrade Read-only Realm File to Latest Version in iOS App - realm

I recently updated Realm in my iOS app to 10.1.2. But then I got a crash that says:
Fatal error: 'try!' expression unexpectedly raised an error: ... "The Realm file format must be allowed to be upgraded in order to proceed." ... Realm file needs upgrade before opening in RO mode Path: ...
This remote.realm file is a user's data they have stored on a remote server that gets downloaded to the iOS app and used for various things. But that remote file is on 3.x while my iOS app is now using 10.x.
I know that opening a Realm in Realm Studio can perform an upgrade, but how do I upgrade/open a read-only Realm file from within my Cocoa app and convert it to the new version?

If you're downloading the file and not re-uploading it somewhere or sharing it between processes, you could catch the error, open it without the readonly flag to perform the upgrade, then re-open it as readonly and return to the caller. I'm not super familiar with the swift API, but in pseudocode, it would look like:
func openRealm(config: Realm.Configuration) -> Realm {
do {
return try Realm(config)
}
catch migrationException {
config.readOnly = false
try! Realm(config)
config.readOnly = true
return try! Realm(config)
}
}

Related

Unity App Crashes When Sign-In via Play Games is Attempted

I have a problem that has been chasing me for the last few days.
I did all the necessary configuration to set up the Google Play Games sign-in method to my Unity game for Android.
However, every time I click the sign-in button the Play Games icon briefly appears at the top and the app suddenly crashes.
Analyzing the logcat, it seems there is an error on the highlighted line (last line of the 'InitializePlayGamesPlatform()' method) of the following script:
using GooglePlayGames;
using GooglePlayGames.BasicApi;
using UnityEngine;
public class UserManager : MonoBehaviour
{
private Firebase.Auth.FirebaseAuth firebaseAuth;
private Firebase.Auth.FirebaseUser firebaseUser;
void Start()
{
InitializePlayGamesPlatform();
}
private void InitializePlayGamesPlatform()
{
PlayGamesClientConfiguration config = new PlayGamesClientConfiguration.Builder()
.RequestServerAuthCode(false)
.Build();
PlayGamesPlatform.InitializeInstance(config);
PlayGamesPlatform.Activate();
************firebaseAuth = Firebase.Auth.FirebaseAuth.DefaultInstance;************
}
public void TrySignIn()
{
UnityEngine.Social.localUser.Authenticate((bool success) =>
{
if (!success)
{
Debug.LogError("UserManager: Failed to sign in into Play Games!");
return;
}
string authCode = PlayGamesPlatform.Instance.GetServerAuthCode();
if (string.IsNullOrEmpty(authCode))
{
Debug.LogError("UserManager: Failed to get auth code!");
return;
}
Debug.LogFormat("UserManager: auth code is: {0}", authCode);
Firebase.Auth.Credential credential = Firebase.Auth.PlayGamesAuthProvider.GetCredential(authCode);
firebaseAuth.SignInWithCredentialAsync(credential).ContinueWith(task =>
{
if (task.IsCanceled)
{
Debug.LogError("UserManager: sign-in was canceled!");
return;
}
if (task.IsFaulted)
{
Debug.LogError("UserManager: error signing in!");
return;
}
firebaseUser = task.Result;
Debug.LogFormat("UserManager: user signed in successfully: {0} ({1})", firebaseUser.DisplayName, firebaseUser.UserId);
});
});
}
public void TrySignOut()
{
firebaseAuth.SignOut();
}
}
Also, there are some other messages/errors in the logcat, such as:
Failed to read Firebase options from the app's resources. Either make sure google-services.json is included in your build or specify options explicitly.
InitializationException: Firebase app creation failed.
at Firebase.FirebaseApp.CreateAndTrack (Firebase.FirebaseApp+CreateDelegate createDelegate, Firebase.FirebaseApp existingProxy) [0x000da] in Z:\tmp\tmp.txs8ldQ514\firebase\app\client\unity\proxy
at Firebase.FirebaseApp.Create () [0x00000] in Z:\tmp\tmp.txs8ldQ514\firebase\app\client\unity\proxy\FirebaseApp.cs:119
at Firebase.FirebaseApp.get_DefaultInstance () [0x0000b] in Z:\tmp\tmp.txs8ldQ514\firebase\app\client\unity\proxy\FirebaseApp.cs:94
at Firebase.Auth.FirebaseAuth.get_DefaultInstance () [0x00000] in Z:\tmp\tmp.poUq23PLco\firebase\auth\client\unity\proxy\FirebaseAuth.cs:294
I repeated every procedure from the beginning a thousand times, searched everywhere and got no results.
I have tried running an older version of GPG plugin as well, but no success at all.
I kindly ask you to help me on this - I promise to put your names on the credits in case I publish!! :)
Thanks in advance!!
A Firebase support member (#Jesus) has just helped me to figure the issue out. The workaround is directly adding the sourceset to the mainTemplate.gradle.
I had to do the following:
Go to Project Settings > Publishing Settings > Build > checkmark Custom Main Gradle Template.
It will give you the location to the mainTemplate.gradle file.
Here is an example.
Go to the given directory and open mainTemplate.gradle with a text editor.
Add the following code to the referred file, right after lintOptions:
sourceSets { main { res.srcDirs += '<full path from your root directory to google-services.xml>' } }
Also, add this array to noCompress under aaptOptions:
noCompress = ['.unity3d', '.ress', '.resource', '.obb', 'google-services.json']
In the end, the mainTemplate.gradle should look like this:
lintOptions {
abortOnError false
}
sourceSets { main { res.srcDirs += 'C:\\Users\\USERNAME\\Documents\\Unity Projects\\GAMENAME\\Assets\\Plugins\\Android\\Firebase\\res\\values\\google-services.xml' } }
aaptOptions {
noCompress = ['.unity3d', '.ress', '.resource', '.obb', 'google-services.json']
ignoreAssetsPattern = "!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~"
}
in my case i have setted prograurd mode in release setting under publish settings>minify>release . Setting this to none have fixed my issue.
That particular issue is related to the google-services.json file that should be automatically included in your build if the file exists in your Assets/ directory. Note that the process is different enough from the Android process that you probably need to ignore the Firebase Android instructions and only follow the Unity ones unless you really know what you're doing.
I'll tackle the easiest problem first. Make sure you have your google-services.json file in your Assets/ directory. I usually keep mine in Assets/Data/ (which is where I also keep things like ScriptableObjects). If you don't have it, follow the instructions on the Download Firebase config file or object help page:
Get config file for your Android app Go to your the Settings icon
Project settings in the Firebase console. In the Your apps card,
select the package name of the app for which you need a config file.
Click google-services.json. Move your config file into the module
(app-level) directory of your app. Make sure that you only have this
most recent downloaded config file in your app.
Once you have that file, you'll need to make sure that Assets/Plugins/Android/Firebase/res/values/google-services.xml gets properly generated:
The reason why this exists is that the Unity SDK does not use the Google Services Gradle Plugin - doing so would break compatibility with older versions of Unity or teams that otherwise opt out of gradle integration. This is why I strongly advise against following any of the Android specific documentation unless you're willing to do a lot of work by hand.
If you do not have google-services.xml or you want to try to regenerate it, you should navigate to Assets>External Dependency Manager>Android Resolver>Force Resolve:
If this does fix your issue, then you should make sure that you enable auto-resolution to avoid this issue in the future:
There are also a few more subtle issues that crop up. One is that "External Dependency Manager for Unity" is a rename of the "Play Services Resolver" (developers kept thinking that it was tied to Play Services - which it isn't). So check that you don't have a Assets/Play Services Resolver directory. Also, if you're using the External Dependency Manager in the Unity Package Manager, make sure that Assets/External Dependency Manager doesn't exist as well. Since you're using two plugins that ship with EDM4U, you may have some duplication (although EDM4U should be smart enough to resolve that).
If you're still running into issues, it may help to share your directory layout WRT where the External Dependency Manager, google-services.json, google-services.xml, and the Firebase and the Play Games Sign-In plugin live. Also it could be worth noting if google-services.xml makes it into an exported project (or your APK). If any of this isn't something you want to share on Stack Overflow, feel free to reach out to Firebase Support and link this SO question.
--Patrick

Microsft Graph Helper fails in the response

I have an ASP.Net App and I recent added login with office 365 consuming Graph Api. It works fine in my local machine and I get token and user info from the Graph Api. But when I deploy the solution in production server I m getting an error in the response from the API. Production server is a virtual windows server 2016
var graphClient = new GraphServiceClient(
new DelegateAuthenticationProvider(
async (requestMessage) =>
{
requestMessage.Headers.Authorization =
new AuthenticationHeaderValue("Bearer", accessToken);
}));
var user = await graphClient.Me.Request()
.Select(u => new {
u.DisplayName,
u.Mail,
u.UserPrincipalName
})
.GetAsync();
This is the code to get the info from the user, after calling this method I get an exeption with the next error:
Method not found: 'System.Threading.Tasks.Task`1<!!0>Microsoft.Graph.BaseRequest.SendAsyc(System.Object, System.Threading.CancellationToken, System.Net.Http.HttpCompletionOption)'.
The most rare is that this happen only in the production server, in test server and local machine it works fine. Thanks in advance!
You are likely missing some dependencies. make sure in your bin folder of the app in production you see the Microsoft.Graph.Core.dll file, sometimes when you deploy things it doesn't update the packages for whatever reason. you should see such a file in your test server and local machines. if not there, copy it over. if it is there, then check that you have the same .net versions installed in prod as you have in other environments. also make sure that in your development environment you have the latest graph api sdk being used.
Finally the solution to solve this problem was updating the .Net framework version in the server.

Session error. The type of the Realm file was invalid

I'm trying to use Realm Object Server, but can't access to data.enter image description here
Can you say why I getting this error?
Platform - Android.
Language - Kotlin.
Realm version - 5.4.0
I just used "fullSynchronization" function on builder.
private val configuration = SyncUser
.current()
.createConfiguration(OutdoorAllyConstants.REALM_OA_REGS_URL)
.waitForInitialRemoteData()
.fullSynchronization()
.build()

Realm Object Server file migration critical issue

I've just upgraded ROS from 2.7.2 to 3.4.2. And now it becomes interesting. Our users can't open their synced realms because of error.
[RLMSyncManager sharedManager].errorHandler = ^(NSError *error, RLMSyncSession *session) {
LogError(#"RLMSyncManager error %#", error);
if (error.code == RLMSyncErrorClientResetError)
{
[self backupBrokenData];
[RLMSyncSession immediatelyHandleError:error.rlmSync_errorActionToken];
return;
}
};
RLMSyncManager returns Error Domain=io.realm.sync Code=8 "(null)" UserInfo={underlying_error=Error Domain=io.realm.sync.auth Code=3 "(null)" UserInfo={statusCode=400}}
And that's fine seems something with our auth credentials on server. But server log tells me: HTTP response: be33008a-ae5e-4fa1-bab2-f11b40f11b55 {"type":"https://realm.io/docs/object-server/problems/invalid-realm-type","title":"The type of the Realm file was invalid.","status":400,"code":619}
Which is basically You're trying to open partial file with non partial configuration. But client and server uses same full realms. And no modifications happened.
Seems this error returned as false positive.
I've tried to grand administrator permission to that user. It could open his database. But as soon I remove admin permission it sees same error chain.
New users is not affected by this migration issue.
Is there anything I could do to let my users connect to their data?
It appears that issue was caused by bug inside realm-object-server, that was successfully fixed in version 3.4.3.
https://github.com/realm/realm-object-server/issues/374

#PutChild Upload file with milton webdav in Mac Finder failed

I'm using milton, and my upload code as follows:
#PutChild
#Transactional
public FileContentItem uploadFile(FolderContentItem parent, String name, byte[] bytes){
String traceId = UuidGenUtil.createUuid();
try {
QUERY_LOGGER.info("[uploadFile][NetdiskController],action=Request, name={}, size={},traceId={}",name,bytes.length,traceId);
In windows, i can upload file successfully, but with Mac Finder, the length of bytes is always 0, and the error as follow:
The Finder can't complete the operation because some data in "Shot.png" can't be read or written (Error code -36)
Anyone know why? Thanks
Update: I try ForkLift webdav client in mac and can upload file successfully
The problem is that mac finder sends first request for creating new file without any byte
After it - call LOCK, which is not available for Dav Level 1, that's why you have bad response from server and mac stop uploading a file. This method availiable only for Dav level 2, so you have to get enterprise license of milton to make it work
After Locking object Finder uploads the file
After - calls UNLOCK method
SO if you want to use mac finder for webdav in milton you have several options:
Get the trial enterprise license and look into this example:https://github.com/miltonio/milton2/tree/master/examples/milton-anno-ref
Realize these methods by yourself by webdav specs
Mock it - extend from MiltonFilter or look into MyOwnServlet in example and in method doFilter/service write something like this:
//mock method, do not use it in production!
HttpServletRequest request = (HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse) resp;
if(request.getMethod().equals("LOCK")){
response.setStatus(200);
response.addHeader("Lock-Token", "<opaquelocktoken:e71d4fae-5dec-22d6-fea5-00a0c91e6be4>");
} else if(request.getMethod().equals("UNLOCK")){
response.setStatus(204);
}else {
doMiltonProcessing((HttpServletRequest) req, (HttpServletResponse) resp);
}
I've checked this code working in the examble by link above: make in web.xml method serving by MyOwnServlet, disable authentication in init by implementing empty security manager, set controller packages to scan "com.mycompany"
p.s. to build the example project I've to delete milton client dependency from pom.xml file

Resources