Android: Application auto backup ki/be kapcsolása (Xamarin is)

Android 6.0 óta (API verzió v23) bevezették az Androidba, hogy az alkalmazás fájljairól biztonsági mentést készít az operációs rendszer a felhasználó Google drive-jára. A backupok mérete maximum 25MB lehet, és az Android a JobScheduler API-jával készülnek 24 órás időintervallumban. További információk itt: https://developer.android.com/guide/topics/data/autobackup

Az érintett fájlok:

  • Shared preferences files
  • Files in the directory returned by getFilesDir()
  • Files in the directory returned by getDatabasePath(String)
  • Files in directories created with getDir(String, int)
  • Files on external storage in the directory returned by getExternalFilesDir(String)

Mivel a Xamarin Essentials a SharedPreferencesbe teszi a Preferences statikus osztály által tárolt adatokat, ezért azok is mentésre kerülnek.

A be/ki kapcsoláshoz az AndroidManifest.xml-ben a következő propertyre van szükség az application tagben:

android:allowBackup="true"

Xamarin Forms / Android: Backspace detektálása az Entrykben

Ahhoz, hogy a szoftveres / hardveres billentyűzeten ütött vissza gomb érzékelését detektáljuk a billentyűzeten, szükségünk lesz egy CustomRenderer-re, ahhoz pedig egy Entry száramaztatáshoz a közös kódban:

public class CustomEntry: Entry
{
    public delegate void BackspaceEventHandler(object sender, EventArgs e);

    public event BackspaceEventHandler OnBackspace;

    public CustomEntry() { }

    public void OnBackspacePressed() 
    {
        if (OnBackspace != null)
        {
            OnBackspace(null, null);
        }
    }
}

Két CustomRenderer megoldás is van Androidon. Az egyik, amelyik magát a Renderert egy InputFilter implementációvá teszi, a másik, amely egy csak egy metódust overrideol. A különbség köztük, hogy a DispatchKeyEvent override az üres entry esetén is továbbítja az eventet, míg az inputfiilter csak akkor érzékeli a visszatörlés gombnyomást, ha volt már szöveg benne.

DispatchKeyEvent override megoldás

public class CustomEntryRenderer: EntryRenderer
 {
    public override bool DispatchKeyEvent(KeyEvent e)
    {
        if (e.Action == KeyEventActions.Down)
        {
            if (e.KeyCode == Keycode.Del)
            {
                if (string.IsNullOrWhiteSpace(Control.Text))
                {
                    var entry = (PasswordBox)Element;
                    entry.OnBackspacePressed();
                }
            }
        }
        return base.DispatchKeyEvent(e);
    }

    protected override void 
    OnElementChanged(Xamarin.Forms.Platform.Android.ElementChangedEventArgs<Entry> e)
    {
        base.OnElementChanged(e);
    }
}

InputFilter implementáció

[assembly: ExportRenderer(typeof(CustomEntry), typeof(CustomEntryRenderer))]
namespace App.Droid.Renderers
{
    public class CustomEntryRenderer: EntryRenderer, Android.Text.IInputFilter
    {
        protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
        {
            base.OnElementChanged(e);

            if (Control == null) 
            {
                return;
            }

            Control.SetFilters(new IInputFilter[] { this });

        }

        ICharSequence IInputFilter.FilterFormatted(ICharSequence source, int start, int end, ISpanned dest, int dstart, int dend)
        {
            if (string.IsNullOrWhiteSpace(source.ToString()))
            {
                var entry = (CustomEntry)Element;
                entry.OnBackspacePressed();
            }
            return source;
        }

    }
}

Xamarin Android: TextView / Entry padding eltávolítása

Ha az iOS Entry láthatólag nem tartalmaz margót vagy paddingot, de Androidon máshogy renderelődik ki, akkor gyanakodhatunk arra, hogy valahol nem állítottunk a Xamarin.Forms kódban margót/paddingot nullára. Azonban a Forms Paddingjával és Marginjával nem állítható az androidos TextView paddingja, ehhez customrenderer-re lesz szükség.

[assembly: ExportRenderer(typeof(CustomEntry), typeof(CustomEntry Renderer))]
namespace banditoth.Droid.Renderers
{
    public class CustomEntryRenderer : EntryRenderer
    {
        protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
        {
            base.OnElementChanged(e);

            if (Control != null)
            {
                // Eltávolítjuk a paddingot.
                Control.SetPadding(0, 0, 0, 0);
            }
        }
    }
}

A Control.SetPaddinggal Custom értékeket állíthatunk be a natív TextView paddingjának. Nekem most az eltávolításra volt szükségem, ezért kinulláztam.

Xamarin Android: SplashScreenActivity és PushNotification megnyitás, kilőtt alkalmazásnál

Alapvetően, ha az alkalmazásunkat PushNotificationból indítja el az Android, és van SplashScreenActivitynk, akkor a MainActivityben nem fogjuk az Extras tömbben megkapni a PushNotification adatait, és nem fogunk tudni reagálni rá.

Mivel a SplashScreenActivity-nk a MainLauncher, ezért ennek az Activitynek az Intent.Extra-jai közé kerülnek be a Pushnotif extrák.

Fontos megjegyezni, hogy az onNewIntent nem fog megfutni terminált alkalmazásnál.

A MainActivity-n az ActivityAttributeban a következőket kell beállítani:

Exported = true, LaunchMode = LaunchMode.SingleTop

A MainActivityben meg kell hívni az onCreate metódusban a következő metódust a LoadApplication hívás után, ha Xamarin esetén a CrossGeeks FirebasePushNotificationPluginját használjuk:

FirebasePushNotificationManager.ProcessIntent(this, Intent);

A SplashScreenActivity ActivityAttributejánál a következőket kell beállítani:

MainLauncher = true, NoHistory = true

A SplashScreenActivity onResume metódusát pedig úgy kell Overrideolni, hogy a MainActivity StartActivityje előtt, kitöltjük az Intent extráit, mintha az Android oprendszer töltötte volna ki a MainActivity számára:

var mainIntent = new Intent(Application.Context, typeof(MainActivity));

 if (Intent.Extras != null) {
     mainIntent.PutExtras(Intent.Extras);
 }
 mainIntent.SetFlags(ActivityFlags.SingleTop);
 StartActivity(mainIntent);