How to overcome RealmMigrationNeededException error on android app - kotlin

When I click on launcher icon of my android app, its crashes immediately. I check logcat error, its shows Migration is required due to the following errors: - Property 'PrintJobData.jobPageCount' has been removed.I'm using Realm database and language is kotlin. How to overcome this issue.
private val realmConfig: RealmConfiguration = RealmConfiguration.Builder()
.name("database.realm")
// .deleteRealmIfMigrationNeeded()
.schemaVersion(1)
.build()
private var realm: Realm = Realm.getInstance(realmConfig)

you can delete your realm if a migration is needed:
.deleteRealmIfMigrationNeeded()
or you can write a custom migration for your realm and each change you make to your database MUST be handled in migration.
NOTE: remember after your changes to your database you have to update schemaVersion and also add your custom migration to RealmConfiguration.Builder() like bellow:
val config = RealmConfiguration.Builder()
.name("yourRealmName.realm")
.schemaVersion(2)
.migration(CustomMigration())
.build()
you can learn how to write migration from this and the original document

Related

Missing Feature{name=auth_api_credentials_begin_sign_in, version=6}

I am trying to use the Google authentication method (One tap sign in) for my application. However, after I clicked on the sign button, I faced the following problems:
W/GoogleApiManager: com.google.android.gms.internal.auth-api.zbaz could not execute call because it requires feature (auth_api_credentials_begin_sign_in, 6).
D/btn click: Missing Feature{name=auth_api_credentials_begin_sign_in, version=6}.
May I know where have I messed up?
I am using MsSQL instead of firebase.
I have created the OAuth 2.0 client.
I am using the Web Client ID for the BuildConfig (I have both Web Client and Android)
buildConfigField : ("String", "CLIENT_ID", '"1113838514547 -neqok16gfh5b77v6hcg33c03d0khs896.apps.googleusercontent.com"')
The google Sign in button was not working with viewBinding so I swapped to "findViewById" for that particular button
Below are the codes:
import android.content.IntentSender
import android.os.Bundle
import android.util.Log
import androidx.activity.result.IntentSenderRequest
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import com.example.myapplication.databinding.ActivitySignInBinding
import com.google.android.gms.auth.api.identity.BeginSignInRequest
import com.google.android.gms.auth.api.identity.Identity
import com.google.android.gms.auth.api.identity.SignInClient
import com.google.android.gms.common.SignInButton
import com.google.android.gms.common.api.ApiException
import com.google.android.gms.common.api.CommonStatusCodes
import com.google.android.material.snackbar.Snackbar
class MainLoginActivity : AppCompatActivity() {
private var _binding: ActivitySignInBinding? = null
private val binding get() = _binding!!
private var sign_in_button : SignInButton? = null
private var oneTapClient: SignInClient? = null
private var signUpRequest: BeginSignInRequest? = null
private var signInRequest: BeginSignInRequest? = null
private val oneTapResult = registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()){ result ->
try {
val credential = oneTapClient?.getSignInCredentialFromIntent(result.data)
val idToken = credential?.googleIdToken
when {
idToken != null -> {
// Got an ID token from Google. Use it to authenticate
// with your backend.
val msg = "idToken: $idToken"
Snackbar.make(binding.root, msg, Snackbar.LENGTH_INDEFINITE).show()
Log.d("one tap", msg)
}
else -> {
// Shouldn't happen.
Log.d("one tap", "No ID token!")
Snackbar.make(binding.root, "No ID token!", Snackbar.LENGTH_INDEFINITE).show()
}
}
} catch (e: ApiException) {
when (e.statusCode) {
CommonStatusCodes.CANCELED -> {
Log.d("one tap", "One-tap dialog was closed.")
// Don't re-prompt the user.
Snackbar.make(binding.root, "One-tap dialog was closed.", Snackbar.LENGTH_INDEFINITE).show()
}
CommonStatusCodes.NETWORK_ERROR -> {
Log.d("one tap", "One-tap encountered a network error.")
// Try again or just ignore.
Snackbar.make(binding.root, "One-tap encountered a network error.", Snackbar.LENGTH_INDEFINITE).show()
}
else -> {
Log.d("one tap", "Couldn't get credential from result." +
" (${e.localizedMessage})")
Snackbar.make(binding.root, "Couldn't get credential from result.\" +\n" +
" (${e.localizedMessage})", Snackbar.LENGTH_INDEFINITE).show()
}
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
_binding = ActivitySignInBinding.inflate(layoutInflater)
setContentView(binding.root)
sign_in_button = findViewById(R.id.sign_in_button)
oneTapClient = Identity.getSignInClient(this)
signUpRequest = BeginSignInRequest.builder()
.setGoogleIdTokenRequestOptions(
BeginSignInRequest.GoogleIdTokenRequestOptions.builder()
.setSupported(true)
// Your server's client ID, not your Android client ID.
.setServerClientId(BuildConfig.CLIENT_ID)
// Show all accounts on the device.
.setFilterByAuthorizedAccounts(false)
.build())
.build()
signInRequest = BeginSignInRequest.builder()
.setGoogleIdTokenRequestOptions(
BeginSignInRequest.GoogleIdTokenRequestOptions.builder()
.setSupported(true)
// Your server's client ID, not your Android client ID.
.setServerClientId(BuildConfig.CLIENT_ID)
// Show all accounts on the device.
.setFilterByAuthorizedAccounts(true)
.build())
.setAutoSelectEnabled(true)
.build()
sign_in_button!!.setOnClickListener{
displaySignIn()
}
}
private fun displaySignIn(){
oneTapClient?.beginSignIn(signInRequest!!)
?.addOnSuccessListener(this) { result ->
try {
val ib = IntentSenderRequest.Builder(result.pendingIntent.intentSender).build()
oneTapResult.launch(ib)
} catch (e: IntentSender.SendIntentException) {
Log.e("btn click", "Couldn't start One Tap UI: ${e.localizedMessage}")
}
}
?.addOnFailureListener(this) { e ->
// No Google Accounts found. Just continue presenting the signed-out UI.
displaySignUp()
Log.d("btn click", e.localizedMessage!!)
}
}
private fun displaySignUp() {
oneTapClient?.beginSignIn(signUpRequest!!)
?.addOnSuccessListener(this) { result ->
try {
val ib = IntentSenderRequest.Builder(result.pendingIntent.intentSender).build()
oneTapResult.launch(ib)
} catch (e: IntentSender.SendIntentException) {
Log.e("btn click", "Couldn't start One Tap UI: ${e.localizedMessage}")
}
}
?.addOnFailureListener(this) { e ->
// No Google Accounts found. Just continue presenting the signed-out UI.
displaySignUp()
Log.d("btn click", e.localizedMessage!!)
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.gms.common.SignInButton
android:id="#+id/sign_in_button"
android:layout_width="129dp"
android:layout_height="52dp"
android:layout_marginStart="141dp"
android:layout_marginTop="252dp"
android:layout_marginEnd="141dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
I was banging my head against the wall for a few days on this issue and finally Alex Mamo helped me solve it. A few things could have caused this issue. First, ensure the following:
User is logged in on a Google account on the emulator.
Both SHA-1 and SHA-256 debug fingerprints are added to the correct project.
The correct google-services.json file is in the correct directory.
The web_client_id is yours and passed correctly into the required fields.
Then if nothing changed, try running the app on a real Android device. By real I mean a device that has been used by real people for some real time and not just a demo physical device conveniently sitting right next you.
If your app still produces the same error, then there are some other issues with the app that I unfortunately cannot help with.
If your app functions correctly on a real device, then it means your emulator is not set up properly. Try spinning up a new emulator and going through the new device configuration process (for me it was called "Setting Up Your Device" and it was available as an actionable notification bar button). This is a separate/different process than simply signing into a Google Account on your Android device. Once complete, wait ten minutes and reboot for good measure. This solved my issue.
Hope this helps!
I got the same error while trying to SignIn using my Android Studio emulator. The problem was a version incompatibility with some plugins.
Broken project build gradle:
id 'com.android.application' version '7.1.3' apply false
id 'com.android.library' version '7.1.3' apply false
Fix:
id 'com.android.application' version '7.1.2' apply false
id 'com.android.library' version '7.1.2' apply false
Furthermore, download again the google-services.json file. It should solve the problem.
Edit: got again the problem and I found out that it is a problem of incompatibility between the API and the version of the emulator. Installing an emulator with API 31 (instead of 32) definitely solved the problem.
In addition to the requirements mentioned by Endian Tribe in his answer, I also had to ensure the following in order to get rid of the error on my emulator:
Use a Google Play system image (Google APIs image didn't work for me).
Set a lock screen pattern or PIN.
Apply any pending system updates (did this via Settings -> Security -> Security/Google Play system update on Android 12).
Not sure if all 3 steps are required but that's what did the trick for me.
In my case I have correct firebase setup (tested before and it worked on same emulator).
Also I've done all steps with authorization in google on device, setup PIN and check for system and google play updates. Nothing changed.
To solve problem I have to manually clear data in Google app on emulator. Then auth in my app worked.
For me the error disappeared in the emulator after installing the Google Play services update as indicated in the screenshots below.
First create an emulator that supports Google Play as "Pixel_4_API_R" or "Pixel_3a_API_28" (see screenshot 1).
Then start the emulator and open the Extended Controls window. There go to "Google Play" and select "Update" (see screenshot 2).
After clicking on the Update button I had to enter a google credential on the phone emulator.
After entering the credentials and confirming a few screens the update of google play services did start automatically on one emulator and on another I had to click the update button again.
Screenshot 1
Screenshot 2

Tracking hangfire background jobs with app insights

I have set up app insights in Asp.net core application. All my web api requests are tracked on app insights and if I have any failures I can simply find them in Failures section.
However, I have also Hangfire background jobs running and if they are failing I can't find them on app insights. Also I have alert rule Whenever the total http server errors is greater than or equal to 1 count and I am not sure if hangfire 5xx errors will go under this condition.
So is there any way to track Hangfire jobs failures and get notified about them?
Hangfire handles most exceptions under the hood, so App Insights is not going to pick them up by default. There is also a bunch of configuration you have to do with App Insights as well.
I wrote a JobFilter for Hangfire which allows you to connect with App Insights, this should be enough to get you going:
https://github.com/maitlandmarshall/MIFCore/blob/master/MIFCore.Hangfire/Analytics/AppInsightsEventsFilter.cs
And for the App Insights configuration:
https://github.com/maitlandmarshall/MIFCore/blob/master/MIFCore.Hangfire/Analytics/TelemetryConfigurationFactory.cs
To put everything together from the above links:
var appInsights = this.rootScope.ResolveOptional<AppInsightsConfig>();
var childScope = ServiceScope = this.rootScope.BeginLifetimeScope("HangfireServiceScope");
var activator = new AutofacLifecycleJobActivator(childScope);
var options = new BackgroundJobServerOptions()
{
Activator = activator,
Queues = new[] { JobQueue.Alpha, JobQueue.Beta, JobQueue.Default, JobQueue.Low }
};
this.globalConfig
.UseFilter(new BackgroundJobContext());
if (!string.IsNullOrEmpty(appInsights?.InstrumentationKey))
{
var telemetryClient = new TelemetryClient(TelemetryConfigurationFactory.Create(appInsights));
this.globalConfig.UseFilter(new AppInsightsEventsFilter(telemetryClient));
}
using (var server = new BackgroundJobServer(options))
{
await server.WaitForShutdownAsync(stoppingToken);
}
There was a nice nuget package created Hangfire.Extensions.ApplicationInsights.
So, install the package:
Install-Package Hangfire.Extensions.ApplicationInsights
and add the line to ConfigureService method:
services.AddHangfireApplicationInsights();
If your solution requires some custom details you can adjust the code from github repository.

How to set property of 'X-IW-SESSION' in Flutter

I am converting my employer's current android app to flutter. One of the difficulties I have been facing recently is how I post data to the server with json.
For some data transactions, the server requires the 'X-IW-SESSION', which is set as follows in the original app:
httpURLConnection.setRequestProperty("X-IW-SESSION", session);
I've tried using the following properties, but I am unable to get the result I need.
Map<String, String> headers = {
HttpHeaders.contentTypeHeader: "application/json",
HttpHeaders.authorizationHeader: session,
};
I checked this over flutter's official documentation. I couldn't find the name 'x-iw-session' but saw something similar = HttpHeaders.authorizationHeader.
In the old android app, the 'x-iw-session' helps the user to login using a session (String) which is stored in the shared preferences.
In the flutter app, I have access to the same session (String), but I am lost as to how should I use the same to login into the server.
Currently, this is what my server sends as response for failure:
{success: false, message: Please Login..You dont have permission}
Please do tell, If I need to show some specific code.
Maybe this would work.
Map<String, String> headers = {
HttpHeaders.contentTypeHeader: "application/json",
”X-IW-SESSION”: session,
};
If so, check for a declaration in HttpHeaders.

Is it possible to ask for ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS permission in hybrid apps?

I would like to create a new mobile application. This new app will be hybrid and will need to be whitelisted. Nowadays, I have an Android native app that request the permission launching the Intent ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS that let the user the possibility of accept/deny the request.
The permission is needed because it is necessary for my app to send data to a private server even if the mobile enters doze/standby mode.
Is it possible to implement something similar using ionic or react-native (I have not decided yet which hybrid technology I will use and any recommendation is appreciated as well).
Thank you!
Yes
On android/app/src/main/AndroidManifest.xml add:
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
On android/app/src/main/java//MainApplication add:
import android.os.PowerManager;
import android.net.Uri;
import android.provider.Settings;
then on function public void onCreate() before SoLoader.init(); add:
Intent myIntent = new Intent();
String packageName = getApplicationContext().getPackageName();
PowerManager pm = (PowerManager) getApplicationContext().getSystemService(Context.POWER_SERVICE);
if (pm.isIgnoringBatteryOptimizations(packageName))
myIntent.setAction(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS);
else {
myIntent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
myIntent.setData(Uri.parse("package:" + packageName));
}
getApplicationContext().startActivity(myIntent);

UniqueConstraints bundle not picked up by EmbeddableDocumentStore with custom plugins directory

We are using EmbeddableDocumentStore for non-production deployments and in general it works great. I stumbled upon an issue which took me few hours to solve and it would be good to know if the behaviour I am experiencing is by design.
I init EmbeddableDocumentStore like this:
var store = new EmbeddableDocumentStore()
{
DataDirectory = dataDirectory,
DefaultDatabase = "DbName",
RunInMemory = false,
UseEmbeddedHttpServer = true,
};
store.Configuration.Port = 10001;
store.Configuration.PluginsDirectory = pluginsDirectory; // this is the important line
store.Configuration.CompiledIndexCacheDirectory = compiledIntexCacheDirectory;
store.Configuration.Storage.Voron.AllowOn32Bits = true;
store.RegisterListener(new UniqueConstraintsStoreListener());
store.Initialize();
With this setup UniqueConstraints are not working on the embedded server.
However, when I put plugins directory to it's default location (WorkingDirectory + /Plugins), it magically starts working. Is it expected behaviour?
More info:
I can reproduce it in Console app and in Web app. In web app, the default location is web root + /Plugins.
After a little bit of investigation I found out that there is a difference in how UniqueConstraints' triggers are registered in store.Configuration.Catalog.Catalogs which might have something to do with the unexpected (for me) behaviour.
With custom PluginDirectory, triggers are registered in store.Configuration.Catalog.Catalogs as BuiltinFitleringCatalog:
When bundle is in the default location, triggers are added to BundlesFilteredCatalog in store.Configuration.Catalog.Catalogs with all other default triggers:
What version of RavenDB?
In RavenDB 3.5 registering plugins on the server-side requires a magic string. Adding this to your example above will probably fix it.
store.Configuration.Settings =
{
{ "Raven/ActiveBundles", "Unique Constraints" }
};