Login Login
MORE

WIDGETS

Widgets

Wanted articles
Who is online?
Article tools

CSharp:Android App - Tips

From Aino Wiki

Jump to: navigation, search

Codice BackEnd

Thread

Come impostare una attesa

//asynchronously: 
await Task.Delay(10000);
 
//synchronously: 
Task.Delay(10000).Wait();

Variabili di ambiente

Nome del dispositivo (doc developer.android.com, Microsoft):

            SharedSetupPar.AppStatus.SO_Type = DeviceInfo.Platform.ToString(); // <-- Android
            SharedSetupPar.AppStatus.DeviceName = Android.OS.Build.Model; // <-- HUAWEI VNS-L31

Verifica e richiesta permessi

#region Gestione Permessi
int sdkApi_info = (int)Build.VERSION.SdkInt; // >= 23
bool isAccessDenied = false;
int nrAttempt4Access = 0;
 
do
{
	strErrorMsg = string.Empty;
	if (ContextCompat.CheckSelfPermission(this, Manifest.Permission.ReadExternalStorage) != (int)Permission.Granted)
	{
		strErrorMsg += "\r\nNON Si dispone dei permessi di LETTURA per l'archivio esterno";
		isAccessDenied = true;
	}
	if (ContextCompat.CheckSelfPermission(this, Manifest.Permission.WriteExternalStorage) != (int)Permission.Granted)
	{
		strErrorMsg += "\r\nNON Si dispone dei permessi di SCRITTURA per l'archivio esterno";
		isAccessDenied = true;
	}
	if (isAccessDenied)
	{
		var permissions = new string[]
							{
							Manifest.Permission.ReadExternalStorage,
							Manifest.Permission.WriteExternalStorage
							};
		ActivityCompat.RequestPermissions(this, permissions, 9); // RequestCode REQUEST_FOLDER_PERMISSION = 9?
		Task.Delay(1000).Wait();
	}
	nrAttempt4Access++;
	isAccessDenied = ContextCompat.CheckSelfPermission(this, Manifest.Permission.ReadExternalStorage) != (int)Permission.Granted
				|| ContextCompat.CheckSelfPermission(this, Manifest.Permission.WriteExternalStorage) != (int)Permission.Granted;
} while (isAccessDenied && nrAttempt4Access < 3);
if (isAccessDenied && nrAttempt4Access == 3)
{
	throw new Exception("Permissions are mandatory!\r\n" + strErrorMsg);
}
#endregion

Oggetti UI

ProgressBar

Quest'oggetto è utilizzabile in due versioni: Hourgrass/Clessidra o Progress bar. Doc ProgressDialog.

Stile clessidra

Segue esempio minimale rifatto ma basato su questa fonte forums.xamarin.com.
Si implementa la modalità "Indeterminate Progress". Si usa un Timer che sostanzialmente fa vedere la clessidra per 10".

<ProgressBar
	android:id="@+id/PrgBarIndet"
	android:layout_width="match_parent"
	android:layout_height="match_parent" />

Altro esempio:

<ProgressBar
	android:id="@+id/progressBar_cyclic"
	android:layout_width="wrap_content"
	android:layout_height="wrap_content"
        android:indeterminate="true"
	android:minHeight="50dp"
	android:minWidth="50dp"
	android:layout_centerVertical="true"
	android:layout_centerHorizontal="true" />

Lato BackEnd:

//..
ProgressBar PrgBarIndet;
//..
System.Timers.Timer m_TimerUI;
private static int m_ProgressBarStatus = 0;
object m_lockRsr = new object();
 
protected override void OnCreate(Bundle savedInstanceState)
{
	//.. dopo il codice di inizializzazione standard
	PrgBarIndet = FindViewById<ProgressBar>(Resource.Id.PrgBarIndet);
}
 
public void MetodoDaClessidra()
{
	StartTimer4PrgBar_Test();
	//Azioni lunghe a seguire
}
 
private void StartTimer4PrgBar_Test()
{
	m_ProgressBarStatus = 0;
	PrgBarIndet.Progress = m_ProgressBarStatus;
	PrgBarIndet.Max = 100;
	m_TimerUI = new System.Timers.Timer();
	m_TimerUI.Enabled = true;
	m_TimerUI.Interval = 1000; // 1 secondo
	m_TimerUI.Elapsed += TimerUI_Elapsed_test;
}
 
private void TimerUI_Elapsed_test(object sender, ElapsedEventArgs e)
{
	RunOnUiThread(() =>
	{
		Log.Info(SharedSetupParams.Dbg_AndroidTAG + "TimerUI_Elapsed"
				, string.Format("m_Prg: {0}, PrgBar: {1}"
								, m_ProgressBarStatus, PrgBarIndet.Progress));
		//PrgBar.IncrementProgressBy(10); //Non influenza la proprietà: PrgBar.Progress
		m_ProgressBarStatus += 10;
		PrgBarIndet.Progress = m_ProgressBarStatus; //La proprietà non è influenzata avrà sempre 0!
		CheckProgress_test();
	});
}
 
public void CheckProgress_test()
{
	lock (m_lockRsr)
	{
		Log.Info(SharedSetupParams.Dbg_AndroidTAG + "CheckProgress"
				, string.Format("m_Prg: {0}, PrgBar: {1}, Visible? {2}."
								, m_ProgressBarStatus
								, PrgBarIndet.Progress
								, PrgBarIndet.Visibility == ViewStates.Visible));
		if (m_ProgressBarStatus >= 100) // FA DURARE LA CLESSIDRA 10 SECONDI !!!!!!!!!!!!!!!!
		{
			Log.Info(SharedSetupParams.Dbg_AndroidTAG + "CheckProgress"
					, string.Format("Reset! m_Prg: {0}, PrgBar: {1}"
									, m_ProgressBarStatus, PrgBarIndet.Progress));
			m_ProgressBarStatus = 0;
			PrgBarIndet.Visibility = ViewStates.Gone;
			m_TimerUI.Dispose();
		}
		else
		{
			PrgBarIndet.Visibility = ViewStates.Visible;
		}
	}
}

Stile ProgressBar

Si implementa la modalità "Determinate Progress". Per indicare la progressione si usa lo stile style="@android:style/Widget.ProgressBar.Horizontal" ed il valore della progressione usando l'attibuto "Progress" (nel seguente esempio si parte da 25%).

<ProgressBar
	android:id="@+id/PrgBarDet"
	style="@android:style/Widget.ProgressBar.Horizontal"
	android:layout_width="match_parent"
	android:layout_height="wrap_content"
	android:visibility="gone"
	android:layout_gravity="center|left"
	android:layout_marginLeft="30dp"
	android:layout_marginRight="30dp" 
	android:progressTint="@android:color/holo_green_light"
	android:indeterminate="false"
	android:max="100"
	android:progress="20"
	android:contentDescription="xxxx"
	/>

Altro esempio

<ProgressBar
	android:id="@+id/progressBar"
	style="?android:attr/progressBarStyleHorizontal"
	android:layout_width="wrap_content"
	android:layout_height="wrap_content"
	android:layout_alignParentLeft="true"
	android:layout_alignParentTop="true"
	android:layout_marginLeft="23dp"
	android:layout_marginTop="20dp"
	android:indeterminate="false"
	android:max="100"
	android:minHeight="50dp"
	android:minWidth="200dp"
	android:progress="1" />

BackEnd. E' necessario che la percentuale di avanzamento sia impostata in un metodo asincrono:

 

ImageButton

Esempio di inserimento di un pulsante con icona del copia in Clipboard:

<ImageButton
	android:id="@+id/ImgBtnPw4Clipboard"
	android:src="?android:attr/actionModeCopyDrawable"
	android:visibility="gone"
	android:layout_width="40dp"
	android:layout_height="40dp"
	android:layout_row="3"
	android:layout_column="2" 
	android:layout_marginRight="0.0dp" 
	android:layout_gravity="right"
	android:contentDescription="@string/LblHnt_ImgBtnPw4Clipboard" />

L'evento da intercettare è Touch

ImageButton ImgBtnPw4Clipboard;
//..
ImgBtnPw4Clipboard = FindViewById<ImageButton>(Resource.Id.ImgBtnPw4Clipboard);
ImgBtnPw4Clipboard.Touch += ImgBtnPw4Clipboard_Touch;
//..
private async void ImgBtnPw4Clipboard_Touch(object sender, View.TouchEventArgs e)
{
	await Clipboard.SetTextAsync(TxtPw4Clipboard.Text);
}

Varie

Cambiare il Focus

Empiricamente è difficile evitare il focus su TextBox se è questo che si vuole per evitare la visualizzazione della tastiera virtuale spostare il focus ad esempio su una ListView come segue:

ListView LVMatchItems = null;
 
//Cambia il Focus per sistemare la situazione odiosa di apertura della tastiera virtuale
LVMatchItems.RequestFocus();

Intercettare pulsante Indietro e chiudere l'App

ATTENZIONE l'handler OnKeyUp() intercetta TUTTI i tasti digitati non solo il tasto "<" per tornare ""indietro.

private static bool m_backExitBtnPressed = false; //<-- usato per evitare uscite involontarie dall'App
//...
public override bool OnKeyUp(Keycode keyCode, KeyEvent e)
{
	try
	{
		//Torna alla PAGINA PRINCIPALE
		if (keyCode == Keycode.Back
			&& !m_isMainView)
		{
			SwitchViewMainEdit(true);
			PrepareForNewSearch();
			//Aggiorna la lista e rieseguire l'ordinamento!
			UpdateListView(TxtItemToSearch_FileName.Text);
			return true;
		}
		//Warining per evitare che per errore si esca dall'App!
		else if (keyCode == Keycode.Back
				&& !m_backExitBtnPressed)
		{
			m_backExitBtnPressed = true;    //Sarà ripristinato dopo l'evento: OnPostResume()
			Toast.MakeText(this, "Sure? Try again to EXIT...", ToastLength.Long).Show();
			return true;
		}
		//Mette in Pausa l'App passando dagli eventi: OnPause() ed infine OnStop()
		else if (keyCode == Keycode.Back)
		{
			Log.Warn(SharedSetupParams.Dbg_AndroidTAG + "OnKeyUp"
					, string.Format("KeyCode='{0}'. Messa in PAUSA dell'App!", keyCode));
			this.Finish();
		}
	}
	catch (Exception ex)
	{
		Log.Error(SharedSetupParams.Dbg_AndroidTAG + "OnKeyUp", ex.Message);
	}
	return true;
}
 
protected override void OnPostResume()
{
	if (m_backExitBtnPressed)
	{ 
		m_backExitBtnPressed = false;
	}
	base.OnPostResume();
}

Condivisione di documenti

Se si vuol condividere ad esempio una immagine o un file si usa facilmente il popup di Android per la condivisione dopo avergli fornito il percorso del file. La libreria da includere è la Xamarin.Essentials
Per documentazione microsoft.com
Sostanzialmente dal seguente esempio si riesce a creare al volo un file di testo ed aprire il popup di invio in condivisione.

using Xamarin.Essentials;
//...
Button BtnShareFile;
 
protected override void OnCreate(Bundle savedInstanceState)
{
      //...
      BtnShareFile.Click += BtnShareFile_Click;
}
 
private void BtnShareFile_Click(object sender, EventArgs e)
{
      try
      {
          ShareFile();
      }
      catch (Exception ex)
      {
          AManager.MessageBox(this, "BtnShareFile_Click", ex.Message);
      }
}
public async Task ShareFile()
{
      var fn = "Attachment.txt";
      var file = Path.Combine(FileSystem.CacheDirectory, fn);
      File.WriteAllText(file, "Hello World");
 
      await Share.RequestAsync(new ShareFileRequest
      {
            Title = Title,
            File = new ShareFile(file)
      });
}

Google Drive

Da approfondire qui [1]
Link interno Android App - Soluzioni avanzate

Autorizzazioni

KeyTool

The MD5 or SHA1 signature of a Xamarin.Android app depends on the .keystore file that was used to sign the APK. Typically, a debug build will use a different .keystore file than a release build. Locate the Xamarin debug.keystore file that is used to sign the app. By default, the keystore that is used to sign debug versions of a Xamarin.Android application can be found at the following location:

C:\Users\USERNAME\AppData\Local\Xamarin\Mono for Android\debug.keystore

Information about a keystore is obtained by running the keytool.exe command from the JDK. This tool is typically found in the following location:

C:\Program Files (x86)\Java\jdkVERSION\bin\keytool.exe

DOC come trovare la propria Keystore Signature docs.microsoft.com
Perchè serve SHA1 fingerprint support.google.com
Per la chiave SH1 di debug ecco come ottenerla:

keytool -list -v \
-alias androiddebugkey -keystore %USERPROFILE%\.android\debug.keystor
oppure
keytool.exe -list -v -keystore "%LocalAppData%\Xamarin\Mono for Android\debug.keystore" -alias androiddebugkey -storepass android -keypass android

Debug

Log

Per verificare cosa succede ad es in fase di installazione dell'APK usare il tool "Logcat" (developer.android.com).
Da Visual Studio cliccare sull'icona in toolbar 'Adb' ed apertasi la finestra terminale digitare:

adb logcat

Dal forum: forums.xamarin.com

Installazione e debug App via USB

Occorre prima abilitare il telefono alla modalità "Developper", successivamente, dal nuovo menu Developper abilitare il Debug via USB.
A questo punto il dispositivo dovrebbe essere visibile ma se non lo fosse si può provare a cambiare la modalità di connessione da MTP (Media Transfer Protocol) a PTP (Picture Transfer Protocol) o RNDIS(USB Ethernet). Per cambiare questa modalità cercare "Select USB Configutation" PTP / MTP / RNDIS
Abilitare anche "Check apps installed via ADB/ADT for harmful behavior"

APK

E' un file archivio contenente il necessario per installare "manualmente" una App Android senza seguire il classico modo attraverso Google Play, con questa modalità occorrerà prima abilitare lo Smartphone all'installazione da "Unknown Sources" (Fonti sconosciute).

Creazione

Il processo corretto per la creazione del file di installazione APK (Android Application Package) è il seguente:

  1. Cambiare la modalità di compilazione da 'Debug' a 'Release'.
  2. Tasto dx sulla Solution (dalla finestra Solution Explorer), e effettuare un "Clean";
  3. Compre prima ma scegliere l'opzione "Rebuild";
  4. Tasto dx sul progetto Android e cliccare su "Archive";
  5. After successful archive click on "Distribute" and click on "Ad-hoc";
  6. Create keystore file;
  7. After finishing click on Open Distribution;

Il file APK è disponibile.

Mappa e Link


C# | Android App | Android Asynchronous programming


Visual Studio | Windows Form | MS SQL | Dizionario


Parole chiave:

Author