Partager via



Février 2018

Volume 33, numéro 2

Cet article a fait l'objet d'une traduction automatique.

C# - Écriture d’applications mobiles natives à l’aide d’un langage de script personnalisable

Par Vassili Kaplan

Dans le numéro de février 2016 de MSDN Magazine, j’a montré comment créer un langage de script personnalisé basé sur l’algorithme de fractionnement et fusion pour l’analyse des expressions mathématiques dans c# (msdn.com/magazine/mt632273). J’ai appelé ma langue du script personnalisable dans c# ou CSCS. Récemment publié un livre électronique qui a fourni le plus de détails sur la création d’un langage personnalisé (bit.ly/2yijCod). Création de votre propre langage de script peut ne pas initialement semble être particulièrement utile, même si certaines applications intéressantes de celle-ci (par exemple, jeu tricherie). J’ai trouvé également certaines applications en matière de programmation Unity.

Mais je découvertes par la suite une application plus intéressante pour un langage de script personnalisable : l’écriture d’applications inter-plateformes pour les appareils mobiles. Il s’avère qu’il est possible d’utiliser CSCS pour écrire des applications pour Android et iOS (et Windows Phone peuvent être facilement ajouté, également). Et le même code peut être utilisé pour toutes les plateformes. Une présentation de la procédure à suivre dans le mois de novembre-décembre 2017 de CODE Magazine publié (codemag.com/article/1711081).

Dans cet article, je vais prendre un approfondissement et montrent comment utiliser CSCS à programmer pour les appareils mobiles. Vous corrigerez également certaines inexactitudes dans l’article CODE Magazine. Vous verrez que tout ce qui peut être effectuée sur la plateforme native peut être effectué dans CSCS. Je vais également pour montrer comment vous pouvez ajouter des fonctionnalités manquantes à CSCS à la volée.

Pour exécuter le code présenté dans cet article, vous devez Visual Studio 2017, avec Xamarin installé, sur Windows ou sur macOS. Visual Studio Community Edition 2017 utiliser personnellement sur mon MacBook. Notez qu’un Mac est nécessaire pour déployer des applications iOS à l’Apple App Store.

Un « Hello, World ! » pour les applications mobiles

Examinons Figure 1, qui affiche un code CSCS de base pour la reconnaissance vocale et de synthèse vocale. Examinons le code ligne par ligne.

Figure 1 « Hello, World ! » dans CSCS pour les applications mobiles

AutoScale();
voice = "en-US";
locButtonTalk = GetLocation("ROOT", "CENTER", "ROOT", "BOTTOM", 0, 0);
AddButton(locButtonTalk, "buttonTalk", "Click me", 200, 80);
AddAction(buttonTalk,  "talk_click");
function talk_click(sender, arg) {
  ShowToast("Please say your name...");
  VoiceRecognition("voice_recog", voice);
}
function voice_recog(errorStatus, recognized) {
  if (errorStatus != "") {
    AlertDialog("CSCS", "Error: " + errorStatus);
  } else {
    ShowToast("Word recognized: " + recognized);
    Speak("Hello, " + recognized, voice);
  }
}

La fonction de l’échelle automatique vous permet d’ajuster automatiquement la taille de widget en fonction de la taille d’écran de périphérique réel. Par exemple, avec l’échelle automatique, la largeur d’un widget sera deux fois plus grande sur un périphérique avec une largeur de 1 280 pixels dans l’autre avec une largeur de 640 pixels. La signature réelle de la fonction de mise à l’échelle est la suivante :

AutoScale(scale = 1.0);

Si vous n’utilisez pas l’échelle par défaut = 1.0 paramètre, le paramètre d’échelle spécifié est appliqué à la différence. Par exemple, si l’échelle = 0,5 la différence de widget tailles lorsque le déplacement de 640 à 1280 pixels n’y aura deux fois, mais 1,5 fois, car la formule pour calculer la nouvelle taille est :

newSize = size + size * scale * (1280 / 640 - 1) = size * (1 + scale) = size * 1.5.

Toutefois, si l’échelle = 2, le widget sera 3 fois supérieur en fonction du calcul. Un cas spécial de mise à l’échelle = 0 satisfait également la formule ici : Aucun ajustement de l’échelle ne sera effectuée, le widget ont exactement la même taille, quelle que soit la taille de l’appareil. Ce paramètre de mise à l’échelle peut également être appliqué par le widget, il peut être spécifié comme un paramètre facultatif dans la fonction GetLocation. J’ai allons montrer comment effectuer cette opération dans un bit.

Ensuite, définir une variable de voix. Notez que CSCS est un langage de script Python-like : le type de la variable est déduit à partir du contexte, donc la variable de la voix est représentée sous forme de chaîne C# en arrière-plan.

Puis définir un bouton. Une définition de widget dans CSCS toujours prend deux instructions : La première indique l’emplacement du widget, et la seconde est la définition réelle du widget. En arrière-plan, un widget UIButton est utilisé pour iOS, et un bouton est utilisé pour Android.

La syntaxe générale pour la création d’un emplacement sur l’écran est la suivante :

GetLocation(ReferenceX, PlacementX, ReferenceY, PlacementY,
            AdjustmentX = 0, AdjustmentY = 0,
            ScaleOption = false, Scale = 0.0, Parent = null);

Voici la signification des arguments :

  • ReferenceX : Le nom d’un autre widget pour la sélection élective horizontal. Il peut être la chaîne « ROOT », ce qui signifie que le widget du parent ou l’écran principal.
  • PlacementX : Un point horizontal par rapport au widget indiqué dans ReferenceX. Les valeurs possibles sont répertoriées à la fin de ces arguments.
  • ReferenceY : Le nom d’un autre widget pour le positionnement vertical. Il peut être la chaîne « ROOT », ce qui signifie que le widget du parent ou l’écran principal.
  • PlacementY : Un point vertical par rapport au widget indiqué dans ReferenceY. Les valeurs possibles sont répertoriées à la fin ces arguments.
  • AdjustmenX : Un déplacement horizontal supplémentaire du widget en pixels. Il peut également être négative ; la direction positive va de gauche à droite.
  • AdjustmenY : Un déplacement vertical supplémentaire du widget en pixels. Il peut également être négative ; la direction positive va du haut vers le bas.
  • ScaleOption : Indique s’il faut appliquer une option de mise à l’échelle spécifique pour le widget. Si cette option a la valeur false ou n’est pas inclus, l’ajustement spécifiée dans la fonction de mise à l’échelle est effectuée. Si l’option est fournie, les paramètres de réglage et de la taille du widget seront modifiées en fonction du paramètre d’échelle.
  • Échelle : La mesure à utiliser pour ajuster la taille du widget. La fonctionnalité est la même que dans la fonction de mise à l’échelle. En fait, le même code sera exécuté.
  • Parent : Le parent du widget. Si non spécifié, le widget sera ajouté à la disposition principale sur Android ou pour le contrôleur d’affichage racine sur iOS (en particulier pour Window.RootViewController.View).

Les valeurs possibles pour les arguments de positionnement sont très semblables à la classe RelativeLayout.LayoutParams Android. Il peuvent s’agir de : « CENTER, » « GAUCHE », « RIGHT », « TOP », « BOTTOM », « ALIGN_LEFT, » « ALIGN_RIGHT », « ALIGN_TOP », « ALIGN_BOTTOM », « ALIGN_PARENT_TOP », « ALIGN_PARENT_BOTTOM ».

Ces paramètres sont utilisés pour la sélection élective horizontale et verticale sur iOS et Android. Aucune base de connaissances XML ou XAML n’est nécessaire. Et il n’existe aucune table de montage séquentiel pour gérer iOS.

Une fois que l’emplacement est créé, vous placez un widget qu’elle contient. Voici la syntaxe générale pour ce faire :

AddWidget(location, widgetName, initParameter, width, height);

AddButton est un cas particulier d’une telle fonction, où l’argument de l’initialisation du texte affiché sur le bouton. Autres exemples de fonctions de widget sont AddLabel, AddView, AddCombobox et il existe beaucoup d’autres, comme vous le verrez.

La fonction AddAction affecte une action à un bouton lorsque l’utilisateur clique dessus. En règle générale, il présente la syntaxe suivante :

AddAction(widgetName, callbackFunction);

Une fonction de rappel dans CSCS a toujours deux paramètres, un expéditeur et un argument de contexte, un concept emprunté à partir de c#.

À l’intérieur de la fonction talk_click, tout d’abord appeler la fonction ShowToast, qui appelle une implémentation de Toast native sur Android et une implémentation personnalisée de type Toast sur iOS. L’implémentation iOS simplement construit une petite image avec un message et détruit après un délai d’attente.

Enfin, appeler à la fonction de reconnaissance vocale :

VoiceRecognition("voice_recog", voice = "en-US");

Le premier paramètre est le nom de la fonction de rappel à appeler lorsque la reconnaissance vocale est terminée. Le deuxième paramètre est la voix. Il est facultatif et, par défaut, il est des États-Unis Anglais. Les voix sont spécifiés (par exemple, ainsi que le code ISO 639-1 pour le nom de langue ISO 3166-1 alpha-2 pour le code de pays « en-US » pour l’anglais, États-Unis, « es-MX » pour l’espagnol, Mexique, « pt-BR », pour portugais, Brésil, etc.).

La signature de la fonction de rappel de reconnaissance vocale est la suivante :

function voice_recog(errorStatus, recognized)

L’argument errorStatus sera une chaîne vide en cas de réussite et une description de l’erreur en cas d’échec. Si la fonction réussit, le mot reconnu est passé comme deuxième paramètre. Si ce n’est pas le cas, une boîte de dialogue alerte s’affichera à l’utilisateur (implémenté comme un UIAlertController sur iOS et comme un AlertDialog.Builder sur Android). Si la reconnaissance vocale est réussie, la fonction de synthèse vocale Speak sera être appelée. Il possède la signature suivante :

Parlez (wordToPronounce, voix = "fr-fr") ;

Les résultats de l’exécution du script Figure 1 figurent dans Figure 2. La figure sur la gauche, représentant un iPhone, illustre la reconnaissance vocale réussie : quand un mot prononcé a été reconnu. La figure sur la droite, représentant un Android, présente une défaillance, lorsqu’il n’existe aucun microphone installé sur le système (souvent le cas lorsque vous utilisez un simulateur).

Un exemple de la « Hello, World ! » en cours d’exécution Script sur iPhone (à gauche) et Android (à droite)
Figure 2 un exemple de la « Hello, World ! » en cours d’exécution Script sur iPhone (à gauche) et Android (à droite)

Structure générale du projet

Où dans le flux de travail sera CSCS d’exécuter le code ? La réponse est différente pour les projets iOS et Android. Elles s’affichent dans ce qui suit, mais tous les détails sont dans le téléchargement de code source associé au github.com/vassilych/mobile.

Le code commun, utilisé par les deux plateformes, est dans la partie du projet partagé, de script. Partagé, qui contient tous les fichiers c# nécessaires pour l’analyse du code CSCS. Le code spécifique à chaque plate-forme est situé dans le scripting.iOS et de script. Projets droid. Afficher la structure d’un exemple de projet dans Figure 3.

Structure générale d’un projet Xamarin avec des scripts CSCS
Structure générale de la figure 3 d’un projet Xamarin avec des scripts CSCS

Le script CSCS se trouve dans le fichier msdnScript.cscs sous le dossier de ressources dans le script. Projet partagé. Notez que vous pouvez inclure d’autres fichiers CSCS en appelant la fonction CSCS suivante :

ImportFile("anotherScriptFile.cscs");

Pour le projet Android configurer un lien vers le fichier msdnScript.cscs à partir de l’écriture de scripts. Dossier de droid actifs et pour le projet iOS configurer un lien à partir du dossier de ressources scripting.iOS. Vous pouvez également référencer le script dans un nombre de différentes manières, par exemple conserver des versions différentes du script sur différentes plateformes.

Le fichier CommonFunctions.cs contient les fonctionnalités communes pour iOS et Android. En particulier, elle contient la méthode qui exécute le script msdnScripting.cscs qui est indiqué dans Figure 4. Notez que puis-je faire la distinction entre le code iOS et Android spécifiques en utilisant les directives de préprocesseur __IOS__ et __ANDROID__. Le code spécifique à la plateforme se trouve principalement dans les projets correspondants, scripting.iOS ou script. Droid.

La figure 4, l’exécution du Script CSCS

public static void RunScript()
{
  RegisterFunctions();
  string fileName = "msdnScript.cscs";
  string script = "";
#if __ANDROID__
  Android.Content.Res.AssetManager assets = MainActivity.TheView.Assets;
  using (StreamReader sr = new StreamReader(assets.Open(fileName))) {
    script = sr.ReadToEnd();
  }
#endif
#if __IOS__
  string[] lines = System.IO.File.ReadAllLines(fileName);
  script = string.Join("\n", lines);
#endif
  Variable result = null;
  try {
    result = Interpreter.Instance.Process(script);
  } catch (Exception exc) {
    Console.WriteLine("Exception: " + exc.Message);
    Console.WriteLine(exc.StackTrace);
    ParserFunction.InvalidateStacksAfterLevel(0);
    throw;
  }
}

Lorsque vous appelez la fonction de RunScript ? Vous pouvez l’appeler uniquement après que la mise en page global a été initialisé, donc vous pouvez ajouter des widgets à celui-ci.

Il s’avère qu’il est plus difficile à cela sur Android à sur iOS : Simplement l’appeler la fonction RunScript à la fin de la fonction MainActivity.OnCreate échoue, car certaines variables n’ont pas encore été initialisés. Par conséquent, vous devez placer RunScript droite avant l’activité principale réellement en cours d’exécution. La documentation Lifestyle d’activité Android à goo.gl/yF8dTZ fournit un indice : Une fois la méthode MainActivity.OnResume terminée, il doit aller directement. Certaines variables globales (par exemple, la taille d’écran, l’orientation et ainsi de suite) ne sont pas initialisés encore même à la fin de la méthode OnResume, donc l’astuce consiste à inscrire un observateur de disposition global à la fin de la méthode OnResume qui est déclenchée dès que global disposition :

protected override void OnResume()
{
  base.OnResume();
  if (!m_scriptRun) {
    ViewTreeObserver vto = TheLayout.ViewTreeObserver;
    vto.AddOnGlobalLayoutListener(new LayoutListener());
    m_scriptRun = true;
  }
}

Notez qu’utiliser une m_scriptRun variable booléenne spécial pour vous assurer que le script s’exécute une seule fois. La méthode OnGlobalLayout dans l’écouteur de mise en page puis exécute le script :

public class LayoutListener : 
  Java.Lang.Object, ViewTreeObserver.IOnGlobalLayoutListener
{
  public void OnGlobalLayout()
  {
    var vto = MainActivity.TheLayout.ViewTreeObserver;
    vto.RemoveOnGlobalLayoutListener(this);
    CommonFunctions.RunScript();
  }
}

Pour iOS, la situation est un peu plus simple, que vous pouvez exécuter le script à la fin de la méthode AppDelegate.FinishedLaunching.

Synthèse vocale

Voyons comment ajouter des fonctionnalités à CSCS, par exemple à l’aide de synthèse vocale.

Tout d’abord, je dois créer une classe dérivant de la classe ParserFunction et remplacer sa méthode Evaluate virtuel protégé, comme indiqué dans Figure 5.

Figure 5 parlent l’implémentation de fonction

public class SpeakFunction : ParserFunction
{
  protected override Variable Evaluate(ParsingScript script)
  {
    bool isList = false;
    List<Variable> args = Utils.GetArgs(script,
         Constants.START_ARG, Constants.END_ARG, out isList);
    Utils.CheckArgs(args.Count, 1, m_name);
    TTS.Init();
    string phrase = args[0].AsString();
    TTS.Voice     = Utils.GetSafeString(args, 1, TTS.Voice);
    TTS.Speak(phrase);
    return Variable.EmptyInstance;
  }
}

Cette classe est simplement un wrapper sur l’implémentation réelle de synthèse vocale. Pour iOS, l’implémentation de synthèse vocale est illustrée dans Figure 6 Android l’implémentation est similaire, mais il prend un peu plus de codage. Vous pouvez le voir dans le téléchargement de code source associé.

La figure 6, iOS mise en œuvre de synthèse vocale (Fragment)

using AVFoundation;
namespace scripting.iOS
{
  public class TTS
  {
    static AVSpeechSynthesizer g_synthesizer = new AVSpeechSynthesizer();
    static public float  SpeechRate { set; get; }      = 0.5f;
    static public float  Volume { set; get; }          = 0.7f;
    static public float  PitchMultiplier { set; get; } = 1.0f;
    static public string Voice { set; get; }           = "en-US";
    static bool m_initDone;
    public static void Init()
    {
      if (m_initDone) {
        return;
      }
      m_initDone = true;
      // Set the audio session category, then it will speak
      // even if the mute switch is on.
      AVAudioSession.SharedInstance().Init();
      AVAudioSession.SharedInstance().SetCategory(AVAudioSessionCategory.Playback,
         AVAudioSessionCategoryOptions.DefaultToSpeaker);
    }
    public static void Speak(string text)
    {
      if (g_synthesizer.Speaking) {
        g_synthesizer.StopSpeaking(AVSpeechBoundary.Immediate);
      }
      var speechUtterance = new AVSpeechUtterance(text) {
        Rate = SpeechRate * AVSpeechUtterance.MaximumSpeechRate,
        Voice = AVSpeechSynthesisVoice.FromLanguage(Voice),
        Volume = Volume,
        PitchMultiplier = PitchMultiplier
      };
      g_synthesizer.SpeakUtterance(speechUtterance);
    }
  }
}

Une fois que vous disposez d’une implémentation, j’ai besoin à incorporer l’analyseur. Cette opération est effectuée dans le projet partagé dans une méthode statique de CommonFunctions.RegisterFunctions (également illustré Figure 3) :

ParserFunction.RegisterFunction("Speak", new SpeakFunction());

Reconnaissance vocale

Pour la reconnaissance vocale ai-je besoin pour utiliser un rappel de fonction afin d’indiquer quelles word à l’utilisateur a été réellement reconnue (ou d’une erreur, comme dans Figure 2).

Je vais implémenter deux fonctions de reconnaissance vocale, une pour démarrer la reconnaissance vocale et l’autre pour l’annuler. Ces deux fonctions sont enregistrées avec l’analyseur comme j’inscrit synthèse vocale dans la section précédente :

ParserFunction.RegisterFunction("VoiceRecognition", new VoiceFunction());
ParserFunction.RegisterFunction("StopVoiceRecognition", new StopVoiceFunction());

L’implémentation de ces deux fonctions pour iOS est indiquée dans Figure 7. Pour Android, l’implémentation est similaire, mais notez que la reconnaissance vocale a été ajoutée à iOS uniquement dans la version 10.0, donc je dois vérifier la version de l’appareil et, si nécessaire, informer l’utilisateur que l’appareil ne prennent en charge dans les versions d’iOS avant 10.0.

Implémentation de la reconnaissance vocale figure 7

public class VoiceFunction : ParserFunction
{
  static STT m_speech = null;
  public static  STT LastRecording { get { return m_speech; }}
  protected override Variable Evaluate(ParsingScript script)
  {
    bool isList = false;
    List<Variable> args = Utils.GetArgs(script,
                          Constants.START_ARG, Constants.END_ARG, out isList);
    Utils.CheckArgs(args.Count, 1, m_name);
    string strAction = args[0].AsString();
    STT.Voice = Utils.GetSafeString(args, 1, STT.Voice).Replace('_', '-');
    bool speechEnabled = UIDevice.CurrentDevice.CheckSystemVersion(10, 0);
    if (!speechEnabled) {
      UIVariable.GetAction(strAction, "\"" +
       string.Format("Speech recognition requires iOS 10.0 or higher.
       You have iOS {0}",
                     UIDevice.CurrentDevice.SystemVersion) + "\"", "");
      return Variable.EmptyInstance;
    }
    if (!STT.Init()) {
      // The user didn't authorize accessing the microphone.
      return Variable.EmptyInstance;
    }
    UIViewController controller = AppDelegate.GetCurrentController();
    m_speech = new STT(controller);
    m_speech.SpeechError += (errorStr) => {
      Console.WriteLine(errorStr);
      controller.InvokeOnMainThread(() => {
        UIVariable.GetAction(strAction, "\"" + errorStr + "\"", "");
      });
    };
    m_speech.SpeechOK += (recognized) => {
      Console.WriteLine("Recognized: " + recognized);
      controller.InvokeOnMainThread(() => {
        UIVariable.GetAction(strAction, "", "\"" + recognized + "\"");
      });
    };
    m_speech.StartRecording(STT.Voice);
    return Variable.EmptyInstance;
  }
}
public class StopVoiceFunction : ParserFunction
{
  protected override Variable Evaluate(ParsingScript script)
  {
    VoiceFunction.LastRecording?.StopRecording();
    script.MoveForwardIf(Constants.END_ARG);
    return Variable.EmptyInstance;
  }
}

Le code de la reconnaissance vocale réel est dans la classe SST. Il est un peu trop long à afficher ici et est également différente pour iOS et Android. Je vous invite à extraire dans le code source qui l’accompagne.

Je n’ai pas une fonction de rappel dans la synthèse vocale, mais vous pouvez ajouter un de la même façon pour indiquer à l’utilisateur à l’issue de la reconnaissance vocale (ou s’il existe une erreur). Le rappel pour le code CSCS est effectué en appelant la méthode UIVariable.GetAction :

public static Variable GetAction(string funcName, string senderName, string eventArg)
{
  if (senderName == "") {
    senderName = "\"\"";
  }
  if (eventArg == "") {
    eventArg = "\"\"";
  }
  string body = string.Format("{0}({1},{2});", funcName, senderName, eventArg);
  ParsingScript tempScript = new ParsingScript(body);
  Variable result = tempScript.ExecuteTo();
  return result;
}

Vous pouvez voir comment cette fonction est utilisée dans Figure 7.

Exemple : Un convertisseur de devise

Ainsi, pour le développement d’application multiplateforme à l’aide de différentes fonctionnalités CSCS, nous allons créer une application à partir de zéro, une conversion de devise.

Pour obtenir des taux de change à jour dans votre application, vous devez utiliser un service en ligne. Vous avez choisi exchangerate-api.com. Le site fournit un service Web de facile à utiliser lorsque les 1 000 premières requêtes par mois sont libres, qui doit être suffisante pour démarrer. Après l’inscription, vous obtenez une clé unique, que vous devez fournir à chaque demande.

Mon application a différentes vues en mode portrait et paysage. Figure 8 montre le mode portrait et Figure 9 montre paysage pour iPhone et Android.

Conversion de devise en Mode Portrait sur iPhone (à gauche) et Android (à droite)
Conversion de devise figure 8 en Mode Portrait sur iPhone (à gauche) et Android (à droite)

Conversion de devise en Mode Paysage sur iPhone (du haut) et Android (du bas)
Conversion de devise figure 9 en Mode Paysage sur iPhone (du haut) et Android (du bas)

La figure 10 contient l’intégralité de l’implémentation de l’application de conversion de devise CSCS.

Mise en œuvre de la figure 10 CSCS de l’application de conversion de devise

function on_about(sender, arg) {
  OpenUrl("http://www.exchangerate-api.com");
}
function on_refresh(sender, arg) {
  currency1 = GetText(cbCurrency1);
  currency2 = GetText(cbCurrency2);
  currency_request(currency1, currency2);
}
function currency_request(currency1, currency2) {
  if (currency1 == currency2) {
    time = Now("HH:mm:ss");
    date = Now("yyyy/MM/dd");
    rate = 1;
  } else {
    url = apiUrl + currency1 + "/" + currency2;
    try {
      data = WebRequest(url);
    } catch(exception) {
      WriteConsole(exception.Stack);
      ShowToast("Couldn't get rates. " + exception);
      SetText(labelRateValue, "Error");
      return;
    }
    try {
      timestamp = StrBetween(data, "\"timestamp\":", ",");
      time      = Timestamp(timestamp, "HH:mm:ss");
      date      = Timestamp(timestamp, "yyyy/MM/dd");
      rate      = StrBetween(data, "\"rate\":", "}");
    } catch(exception) {
      ShowToast("Couldn't get rates. " + exception);
      SetText(labelRateValue, "Error");
      return;
    }
  }
  SetText(labelRateValue, rate);
  SetText(labelDateValue, date);
  SetText(labelTimeValue, time);
}
function init() {
  currencies = {"EUR", "USD", "GBP", "CHF", "JPY", "CNY", "MXN", "RUB", "BRL", "SAR"};
  flags      = {"eu_EU", "en_US", "en_GB", "de_CH", "ja_JP", "zh_CN",
                "es_MX", "ru_RU", "pt_BR", "ar_SA"};
  AddWidgetData(cbCurrency1, currencies);
  AddWidgetImages(cbCurrency1, flags);
  SetSize(cbCurrency1, 80, 40);
  SetText(cbCurrency1, "USD");
  AddWidgetData(cbCurrency2, currencies);
  AddWidgetImages(cbCurrency2, flags);
  SetSize(cbCurrency2, 80, 40);
  SetText(cbCurrency2, "MXN");
  SetImage(buttonRefresh,     "coins");
  AddAction(buttonRefresh,    "on_refresh");
  SetFontColor(buttonRefresh, "white");
  SetFontSize(buttonRefresh,  20);
  AddAction(aboutButton,      "on_about");
}
function on_portrait(sender, arg) {
  AddOrSelectTab("Rates", "rates_active.png", "rates_inactive.png");
  SetBackground("us_bg.png");
  locCurrency1 = GetLocation("ROOT", "LEFT", "ROOT", "TOP", 10, 80);
  AddCombobox(locCurrency1, "cbCurrency1", "", 280, 100);
  locCurrency2 = GetLocation("ROOT", "RIGHT", cbCurrency1, "CENTER", -10);
  AddCombobox(locCurrency2, "cbCurrency2", "", 280, 100);
  locRateLabel = GetLocation("ROOT", "CENTER", cbCurrency2, "BOTTOM", -80, 60);
  AddLabel(locRateLabel, "labelRate", "Rate:", 200, 80);
  locRateValue = GetLocation("ROOT", "CENTER", labelRate, "CENTER", 100);
  AddLabel(locRateValue, "labelRateValue", "", 240, 80);
  locDateLabel = GetLocation("ROOT", "CENTER", labelRate, "BOTTOM", -80);
  AddLabel(locDateLabel, "labelDate", "Date:", 200, 80);
  locDateValue = GetLocation("ROOT", "CENTER", labelDate, "CENTER", 100);
  AddLabel(locDateValue, "labelDateValue", "", 240, 80);
  locTimeLabel = GetLocation("ROOT", "CENTER", labelDate, "BOTTOM", -80);
  AddLabel(locTimeLabel, "labelTime", "Time:", 200, 80);
  locTimeValue = GetLocation("ROOT", "CENTER", labelTime, "CENTER", 100);
  AddLabel(locTimeValue, "labelTimeValue", "", 240, 80);
  locRefresh = GetLocation("ROOT", "CENTER", "ROOT", "BOTTOM", 0, -4);
  AddButton(locRefresh, "buttonRefresh", "Convert", 200, 100);
  AddOrSelectTab("Settings", "settings_active.png", "settings_inactive.png");
  locAbout = GetLocation("ROOT", "CENTER", "ROOT", "BOTTOM", -4);
  AddButton(locAbout, "aboutButton", "Powered by exchangerate-api.com", 360, 100);
}
function on_landscape(sender, arg) {
  AddOrSelectTab("Rates", "rates_active.png", "rates_inactive.png");
  SetBackground("us_w_bg.png");
  locCurrency1 = GetLocation("ROOT", "LEFT", "ROOT", "CENTER", 50);
  AddCombobox(locCurrency1, "cbCurrency1", "", 200, 120);
  locCurrency2 = GetLocation(cbCurrency1, "RIGHT", "ROOT", "CENTER", 40);
  AddCombobox(locCurrency2, "cbCurrency2", "", 200, 120);
  locDateLabel = GetLocation(cbCurrency2, "RIGHT", "ROOT", "CENTER", 60);
  AddLabel(locDateLabel, "labelDate", "Date:", 180, 80);
  locDateValue = GetLocation(labelDate, "RIGHT", labelDate, "CENTER", 10);
  AddLabel(locDateValue, "labelDateValue", "", 220, 80);
  locRateLabel = GetLocation(cbCurrency2, "RIGHT", labelDate, "TOP", 60);
  AddLabel(locRateLabel, "labelRate", "Rate:", 180, 80);
  locRateValue = GetLocation(labelRate, "RIGHT", labelRate, "CENTER", 10);
  AddLabel(locRateValue, "labelRateValue", "", 220, 80);
  locTimeLabel = GetLocation(cbCurrency2, "RIGHT", labelDate, "BOTTOM", 60);
  AddLabel(locTimeLabel, "labelTime", "Time:", 180, 80);
  locTimeValue = GetLocation(labelTime, "RIGHT", labelTime, "CENTER", 10);
  AddLabel(locTimeValue, "labelTimeValue", "", 220, 80);
  locRefresh = GetLocation("ROOT", "CENTER", "ROOT", "BOTTOM", 0, -4);
  AddButton(locRefresh, "buttonRefresh", "Convert", 180, 90);
  AddOrSelectTab("Settings", "settings_active.png", "settings_inactive.png");
  locAbout = GetLocation("ROOT", "CENTER", "ROOT", "BOTTOM", -4);
  AddButton(locAbout, "aboutButton", "Powered by exchangerate-api.com", 360, 100);
}
AutoScale();
apiUrl = "https://v3.exchangerate-api.com/pair/c2cd68c6d7b852231b6d69ee/";
RegisterOrientationChange("on_portrait", "on_landscape");
init();
if (Orientation == "Portrait") {
  on_portrait("", "");
} else {
  on_landscape("", "");
}
SelectTab(0);

On_refresh et fonctions on_about sont les deux rappels se produisent lorsque l’utilisateur clique sur un bouton.

La méthode on_about est exécutée lorsque l’utilisateur clique sur le bouton « Alimenté par » dans l’onglet Paramètres, ce qui entraîne la fonction OpenUrl ouvrir la exchangerate-api.com page d’accueil dans le navigateur par défaut (cet onglet n’est pas indiqué dans Figure 8 et Figure 9). La méthode on_refresh est exécutée lorsque l’utilisateur clique sur le bouton Convertir. Vous obtenez ensuite les devises sélectionnées et la fonction de currency_request CSCS est appelée, ce qui effectue la conversion de la vitesse réelle.

La fonction currency_request vérifie d’abord si les deux devises sont identiques : dans ce cas vous savez déjà que le taux est 1, et il n’est pas nécessaire pour appeler un service Web (je souhaite enregistrer mes libre utilise limitée de ce service par mois). Sinon, la fonction WebRequest est appelée. Cette fonction est courant pour les deux iOS et Android et son implémentation est indiquée dans Figure 11. Notez que vous n’avez à faire de la gestion des exceptions en code c#. Si une exception est levée (par exemple, si le service n’est pas disponible), l’exception sera propagée au code CSCS, où elle est interceptée. Notez également que la fonction WebRequest est implémentée de façon synchrone. Vous pouvez également rendre asynchrone à l’aide de la fonction de rappel à appeler lorsque la demande est effectuée (analogue à la fonctionnalité de reconnaissance vocale illustré précédemment).

Implémentation de la figure 11 c# de le WebRequestFunction évaluer (méthode)

public class WebRequestFunction : ParserFunction
{
  protected override Variable Evaluate(ParsingScript script)
  {
    bool isList = false;
    List<Variable> args = Utils.GetArgs(script,
                          Constants.START_ARG, Constants.END_ARG, out isList);
    Utils.CheckArgs(args.Count, 1, m_name);
    string uri = args[0].AsString();
    string responseFromServer = "";
    WebRequest request = WebRequest.Create(uri);
    using (WebResponse response = request.GetResponse()) {
      Console.WriteLine("{0} status: {1}", uri,
                        ((HttpWebResponse)response).StatusDescription);
      using (StreamReader sr = new StreamReader(response.GetResponseStream())) {
        responseFromServer = sr.ReadToEnd();
      }
    }
    return new Variable(responseFromServer);
  }
}

Nous allons continuer à l’analyse du code CSCS dans Figure 10. J’ai décrivant que se passe-t-il dans la fonction currency_request. Obtenir à partir de la réponse de JSON exchangerate-api.com présente l’aspect suivant :

{"result":"success","timestamp":1511464063,"from":"USD","to":"CHF",­"rate":­0.99045395}

L’horodatage est le nombre de secondes écoulées depuis le 1er janvier 1970. La fonction CSCS Timestamp(format) convertit ce nombre de secondes pendant lesquelles un format d’heure ou la date spécifiée.

StrBetween (données, strStart, strEnd) est une fonction pratique pour extraire une sous-chaîne de la chaîne de données entre des chaînes strStart1 et strStart2.

Une fois que la vitesse, la date et l’heure extraire, elles définies pour les étiquettes correspondants à l’aide de la fonction SetText (widgetName, texte).

Dans la fonction init initialiser les données, et je peux ajouter des devises supplémentaires pour la conversion.

Il est facile de différentes dispositions pour différentes orientations : enregistrer des rappels de modification de l’orientation avec la fonction RegisterOrientationChange. Les fonctions on_portrait et on_landscape sont appelées à chaque modification de l’orientation du périphérique. Comme vous pouvez le voir en bas de Figure 10, il est défini en appelant :

RegisterOrientationChange("on_portrait", "on_landscape");

Pour ajouter des widgets à l’écran à des emplacements spécifiques, en général à l’aide de la logique expliqué dans l’exemple « Hello, World ! » dans la première section. Vous avez probablement remarqué que les arrière-plans de téléphone différent pour le mode paysage et portrait. Cette opération est effectuée à l’aide de la fonction SetBackground(imageName) CSCS.

AddOrSelectTab fonction a la signature suivante :

AddOrSelectTab(Tab_Name, Picture_when_active, Picture_when_inactive);

Si le l’onglet n’existe pas encore, il est ajouté, sinon il sera sélectionné et tous les widgets consécutifs seront ajoutés à cet onglet. Figure 12 présente l’aspect des onglets dans les modes actives et inactives.

Active et onglets inactif sur iOS
Figure 12 actif et inactif d’onglets sur iOS

Pour résumer

Dans cet article vous a appris qu’avec CSCS, vous pouvez programmer des applications mobiles à l’aide d’un langage de script. Le script est converti en code natif à l’aide de l’interpréteur c# et l’infrastructure Xamarin. Les scripts CSCS faire tout ce qui peut être effectué en c# (et dans Xamarin c#, vous pouvez faire tout ce qui peut être effectué dans le développement d’applications natives).

J’ai déjà publié une application écrite entièrement en CSCS. Extraire la version iOS à apple.co/2yixGxZ et la version Android à goo.gl/zADtNb.

CSCS script pour les applications mobiles est loin d’être terminée. Pour ajouter de nouvelles fonctionnalités à CSCS, vous créez une classe qui dérive de la classe ParserFunction et remplacez sa méthode d’évaluation. Vous inscrivez ensuite cette classe avec l’analyseur, en fournissant son nom CSCS :

ParserFunction.RegisterFunction("CSCS_Name", new MyNewCustomFunction())

À l’aide de CSCS vous pouvez placer tous les widgets par programme et le même code servira pour Android et iOS. Et vous n’avez pas besoin d’utiliser n’importe quel XAML pour ce faire, comme vous le feriez avec Xamarin.Forms.

Vous pouvez également combiner CSCS avec le code c# existant, il est facile d’appeler du code c# à partir de CSCS, comme expliqué à codemag.com/article/1711081. Dans cet article, vous pouvez également vérifier la liste des fonctions implémentées dans CSCS. Mais pour les plus récentes, dernières CSCS fonctions et fonctionnalités, visitez github.com/vassilych/mobile.

Malheureusement, il n’existe aucune place pour discuter des choses intéressantes que vous pouvez faire dans CSCS, comme dans l’application d’achat et des publications de facturation, dans l’application, planification des événements Shot et répétitives et bien plus encore, mais vous pouvez les extraire dans le code source associé télécharger.

Vassili Kaplanest un kit de développement Microsoft Lync précédent. Il est passionné de la programmation en c#, C++, Python et présent dans CSCS. Actuellement, il se situe à Zurich, Suisse et fait Office de traducteur indépendant pour différentes banques. Vous pouvez contacter à l’adresse iLanguage.ch

Merci à l'expert technique Microsoft suivant d'avoir relu cet article : James McCaffrey
Dr. James McCaffrey travaille pour Microsoft Research à Redmond, Washington Il a travaillé sur plusieurs produits Microsoft, y compris Internet Explorer et Bing. Dr. McCaffrey peut être atteint à jamccaff@microsoft.com.


Discussion sur cet article sur le forum MSDN Magazine