Critical Hit Technologies https://criticalhittech.com winning solutions for a high tech world Wed, 07 Jun 2023 22:30:12 +0000 en-US hourly 1 https://wordpress.org/?v=6.7.1 https://i0.wp.com/criticalhittech.com/wp-content/uploads/2018/12/cropped-Critical_Hit_Technologies_logo_B.png?fit=32%2C32&ssl=1 Critical Hit Technologies https://criticalhittech.com 32 32 110204929 Xamarin.Forms and MAUI app Accessibility https://criticalhittech.com/2023/06/07/xamarin-forms-and-maui-app-accessibility/ https://criticalhittech.com/2023/06/07/xamarin-forms-and-maui-app-accessibility/#respond Wed, 07 Jun 2023 22:23:44 +0000 https://criticalhittech.com/?p=1888 Note: Some users who installed XamRight recently (about May 22 – June 7, 2023) had their trial period end early (often within a day). If this happened to you, install the latest version from the marketplace (XamRight 4.2 or later) to automatically have a new trial period start, or contact us for assistance.

There are many good reasons to consider accessibility in app development — including reaching more users and complying with governmental regulations. Microsoft has an interesting and detailed writeup with their commitment to accessibility.

When it comes to developing apps, there are many things to consider in accessibility, including high-level UX design. This post focuses on just two important areas of accessibility: content descriptions for screen readers and color contrast can be addressed by appropriate use of Xaml properties.

We include examples of warnings generated by XamRight as examples of the kinds of problems you’ll need to address, but whether or not you use XamRight, we hope these examples will help you on your journey to building accessible applications.

Supporting Screen Readers

Screen readers are a form of assistive technology that render text content to speech. They are essential to users with visual impairments who cannot rely exclusively on understanding what’s on the screen.

Xamarin.Forms and .NET MAUI have been getting better at providing reasonable default behavior for screen readers, but there are still gaps in how these defaults work with screen readers in terms of clearly presenting all of the information and options available. The app might be usable, but users who cannot see the screen will have a very poor experience.

There are several properties available that guide screen readers to give a better experience. These properties are part of the AutomationProperties class and the SemanticProperties class in .NET MAUI, which map to the native accessibility API on Android, iOS and Windows and give you more control over how screen readers would treat elements in your user interface.

The most commonly used properties include:

XamRight provides guidance on when to use these AutomationProperties for elements in Xaml code so you can eliminate some of the most common accessibility issues.

For example, it can suggest setting AutomationProperties.Name or HelpText on selectable controls such as Button, reminding you to describe their function for the benefit of screen reader users. Without additional context, a user with a screen reader might not understand why they would click “Ok”.

XamRight warns when elements are missing AutomationProperties for screen readers

XamRight also detects when you have views such as Image that need to enable AutomationProperties.IsInAccessibleTree in order for screen readers to focus on them. It can set this property for you in one click too, so you can save time typing. Note that by default, Image is included in the accessibility tree in MAUI, so the main reason for AutomationProperties.IsInAccessibleTree in MAUI would be to set it to false for purely decorative images.

Warning when an Image element is not visible to screen readers

There are a lot of code-level decisions that can make or break your app’s accessibility, such as selecting controls that don’t support AutomationProperties, like EntryCell, which makes it impossible to make this aspect of your app accessible. Instead, you would need to rewrite the EntryCell to a more accessible alternative implementation.

Warning when using built-in cells that do not support AutomationProperties

Drag/swipe gestures can be problematic for accessibility; people with visual or motor disabilities find them challenging to use. These should be handled carefully to make sure there is an alternate, accessible way to access that functionality.

Warning about using inaccessible drag gesture recognizer

The exact behavior of a screen reader depends on the device, implementation and use case and so it is recommended that you always test your app manually with a screen reader. However, like with many other kinds of bugs, using static analysis tools like XamRight shortens your testing cycle.

Color Contrast

All users can benefit from good color contrast in an app: people with low vision and color blindness may have a hard time seeing the difference between colors that are too similar, but even fully sighted people can get frustrated trying to read content with poor color contrast.

There are clear standards for color contrast defined by the Web Content Accessibility Guidelines. All of the color choices in your application, both in Light Mode and Dark Mode, will affect the color contrast as seen by users. See this post for a more in-depth look at the details of Dark Mode and Xamarin.Forms.

While color contrast is important to understand for all elements of your UI, XamRight focuses on text color contrast. Unfortunately, the defaults for Xamarin.Forms and MAUI controls don’t always provide good contrast in both Light and Dark Mode by default.

The color displayed on the screen is a combination of platform defaults, Style resources and properties on elements of the Xaml tree. Since XamRight analyzes all of the Xaml files in an application, it is able to compute color contrast when it sees color properties like TextColor, DetailColor and BackgroundColor set on elements and pages.

XamRight’s color contrast warning tells you which elements have poor color contrast

Conclusion

Developers may think of accessibility features as something optional, but it’s really in everyone’s best interest to implement them. You will improve how people with disabilities experience your app and make your app inclusive of more users. In a growing number of places, making applications accessible has also become the law, but you don’t need to wait for that to happen before you begin thinking about accessibility.

While this post focuses on two key areas of accessible app development, there are additional ways to improve accessibility, including more platform features and UX design. However, content labeling and good color contrast are important foundations for any accessible app developer to understand.

If you have a Xaml-based Xamarin.Forms or MAUI app, the accessibility checks in XamRight are a great place to get started today!

]]>
https://criticalhittech.com/2023/06/07/xamarin-forms-and-maui-app-accessibility/feed/ 0 1888
XamRight for WPF and More License Options https://criticalhittech.com/2023/05/23/xamright-for-wpf-and-more-license-options/ https://criticalhittech.com/2023/05/23/xamright-for-wpf-and-more-license-options/#respond Tue, 23 May 2023 16:19:00 +0000 https://criticalhittech.com/?p=2255 Continue reading "XamRight for WPF and More License Options"]]> With the XamRight 4.0, we excited to release support for WPF Xaml, adding it to the list of supported Xaml variants, along with Xamarin.Forms and .NET MAUI. Another much-asked-for change in this release is different licensing options at different price points. There are additional improvements we will be blogging about soon, and you can see an overview in XamRight Release Notes.

XamRight for WPF

After years of work to refactor, extend, and thoroughly test the XamRight analysis engine, we are proud to announce that XamRight now supports analyzing WPF applications in addition to Xamarin.Forms and .NET MAUI applications.

Our beta testers for XamRight for WPF included developers at Fortune 500 companies as well as companies of only a handful of developers. With that breadth of testers, we are confident in launching WPF support.

What does this mean? If you are a WPF developer, you can now use XamRight to get automatic Xaml intellisense, advanced error checking, Xaml refactoring, navigation, and more. Get a 25% early adopter discount by purchasing your XamRight Pro WPF license before July 31, 2023.

Price and License Changes

We’re happy to announce more options for licensing, and, in our fight against inflation, lower prices.

CompleteIntellisense, real-time error checking, tooltips, refactoring, navigation, suggested fixesBoth cross platform (Maui/Xamarin) and WPFConcurrent install on up to 3 machines$129/year
ProIntellisense, real-time error checking, tooltips, refactoring, navigation, suggested fixesEither cross platform (Maui/Xamarin) or WPFConcurrent install on up to 3 machines$89/year
StandardIntellisense, real-time error checking, tooltipsEither cross platform (Maui/Xamarin) or WPF1 machine$49/year
CommunityOn demand error checkingN/AN/AFree

Note that all licenses are single user, but Complete and Pro licenses support multiple machines (work/home/desktop/laptop/PC/Mac). Go to our online store for details and to order.

]]>
https://criticalhittech.com/2023/05/23/xamright-for-wpf-and-more-license-options/feed/ 0 2255
Deploying Xamarin and Maui apps from Azure Pipelines to Google Play https://criticalhittech.com/2023/05/16/deploying-xamarin-and-maui-apps-from-azure-pipelines-to-google-play/ https://criticalhittech.com/2023/05/16/deploying-xamarin-and-maui-apps-from-azure-pipelines-to-google-play/#respond Tue, 16 May 2023 22:21:34 +0000 https://criticalhittech.com/?p=2069 Continue reading "Deploying Xamarin and Maui apps from Azure Pipelines to Google Play"]]> Being able to deploy directly to an app store from a CI/CD pipeline is incredibly convenient, improves repeatability, and generally a good practice. But there are several pieces that have to be put in place to get it running. We’ve had to do it multiple times, so we ended up writing this up as a walkthrough for ourselves, starting almost from File > New Project. Hopefully it will be as helpful for the rest of the Xamarin/Maui community.

Most of this blog post was written using a Xamarin.Android application, but the same process works for Maui Android applications. This is focused on deployed AAB files, which is the preferred format (as of the time of writing, anyway).

This walkthrough assumes you have not published your app at all yet. If you are already building and publishing, and want to skip ahead to the part where you’re deploying directly from your DevOps Pipeline, start here.

Preparing your Android app for release

Before setting up your build pipeline, you first need to ensure that your Xamarin.Android application build properties are setup according to the necessary configurations, as well as to your application’s requirements.

First, create a custom configuration option for building your Android application to publish to the Google Play Store. Select ‘Configuration Manager’ under the build option dropdown as shown below:

Then on the popup dialog under ‘Active solution configuration’ select <New…>

Provide a name for your configuration. For this sample, we will name it ‘PlayStore’ Uncheck the option to ‘Create new project configurations’ and click OK.

Then edit the Configuration column for the Android project. Select <New…> under the Configuration column for the Android project and provide the same name ‘PlayStore.’ Uncheck the ‘Create new solution configurations’ option and click OK.

Now you’re all set to begin editing the Android options for publishing to the Google Play Store. Below are some of the properties that need to be altered:

  • Disable debugging

    In order to package and publish your Android application, the android:debuggable property in the AndroidManifest.xml file needs to be set to false. A better way to do this is to use a conditional compile statement in your AssemblyInfo.cs as noted in the documentation here.
  • Packaging your application

    You can choose to package your application as an .apk or an .aab file. For this sample we will choose .aab which is the more recent packaging format. For more information on app bundles see.

    Right click on your Android project and select Properties. Then choose Android Options as shown in the image below. Under Android Package Format select bundle.
  • Disable ‘Use Fast Deployment’
    This option should be disabled as it is only meant for debugging. To disable this option, navigate to Android Options and uncheck “Use Fast Deployment” as shown above.
  • Specify Compiler and Code Shrinker
    Choosing the right compiler and code shrinker will speed up the startup time of your Android application. You can specify the compiler architecture and code shrinker on the Android Options dialog as well.
    For this sample, we’ve chosen the d8 compiler that is paired with the r8 code shrinker. You can read more about the compiler and shrinker options here.
  • Specify supported architectures
    Specify which CPU your application supports by selecting the Advanced button at the bottom of the Android Options page.

Now that your application build properties are setup, you can now generate a keystore file for signing your application’s aab.

Generating a keystore file

To generate a keystore file right click on your Android project and select archive. This will bring up the Archive Manager and generate your application bundle.


Take note of the Bundle Format on the generated archive and ensure that it is set to aab. Also take note of the Version and Version Code properties. This will correspond to the android:versionCode and android:versionName properties in the AndroidManifest.xml file. These have to be updated for each app build published to Google Play. A convenient way to generate unique version numbers for CI/CD scenarios is the Mobile App Tasks for iOS and Android DevOps extension.

Now select the generated archive and click Distribute. The popup below should appear. Select Ad Hoc.

The ‘Signing Identity’ page will appear. Click on the + sign to create a new Keystore file. Enter the values for Alias and Password and make sure you store them in a save place as these values will also be used later when setting up the Azure Pipeline.


The keystore file generated will be saved in the folder C:\Users\<your-alias>\AppData\Local\Xamarin\Mono for Android\Keystore\Your_KeyStoreFileAlias. Now that you have generated the keystore file, select ‘Save As’ on the same popup and choose where you would like to save the signed aab file.

Now that you have your application bundle file, you can set up a new application in the Google Play Console to host your Android application.

It is important to note that you will have to add your generated bundle manually for the first time before setting up the Azure Pipeline to push newer versions to the console. This will be described below.

Setting up your application in the Google Play Console

After initial application setup, drop the first version of the application by selecting your application in the Dashboard and then selecting Testing > Internal testing. Select the option to “Create new release” and proceed to upload your aab.

Now that you’ve dropped your first version, you can add a list of testers on the ‘Testers’ tab. This step is also necessary to initialize the Google Play entry to allow subsequent deployments to succeed from Azure DevOps.

Connection between Azure DevOps and Google Play

The next step is to create a Google Cloud service account and install the Google Play DevOps extension to your Azure DevOps Organization. Note that this is installed at the Organization level, not the individual Project level.

The link above has instructions on how to go through the Google Play Developer Console to create a Google Play service account, and this page has a more in-depth walkthrough. That page is focused on publishing through App Center, so while the initial steps apply to both App Center and Azure DevOps, stop at the instructions specific to App Center.

Once the extension is installed in the Organization and the service account is created, follow the directions to create a Project-specific service connection. In the example below, we assume the service connection is called Google Play Publishing.

Completing the DevOps Pipeline configuration

For this section, we start with a standard Maui Azure Pipeline yaml created by DevOps (for instance, this from a Microsoft sample Maui app).

The two important changes are to sign the build and to publish the signed AAB.

First, upload your keystore as a secure file to your Pipeline Library. Define the keystore password, key alias and key password as secret pipeline variables, then update the build step to:

- task: DotNetCoreCLI@2
  displayName: 'Build and sign Android target'
  inputs:
    command: 'publish'
    projects: '**/*.csproj'
    publishWebProjects: false
    arguments: '-c $(buildConfiguration) -f net6.0-android -p:AndroidPackageFormat=aab -p:AndroidKeyStore=True -p:AndroidSigningKeyStore=$(keystore.secureFilePath) -p:AndroidSigningStorePass=$(<var name for keystore password>) -p:AndroidSigningKeyAlias=$(<var name for key alias>) -p:AndroidSigningKeyPass=$(<var name for key password>)'

If your build has other options (e.g. targeting net7.0), merge in the signing-related arguments.

Next, add the task to publish to Google Play:

- task: GooglePlayRelease@4
  displayName: 'Publish to Google Play'

  inputs:
    applicationId: 'com.<your-org>.<your-app>'
    serviceConnection: 'Google Play Publishing'
    action: 'SingleBundle'
    bundleFile: '$(outputDirectory)/*-Signed.aab'
    track: 'internal'
    userFraction: '1.0'

Depending on your build setup, you may need to tweak the bundleFile value. There are a bunch of other options for the GooglePlayRelease task, but this is enough for a basic scenario of publishing to the internal test track.

You will probably also want a branch filter on this task (if you don’t have one on the entire Pipeline) to avoid having dev branches accidentally overwrite more official builds that you want published to the specific track.

Run the Pipeline

Now run the Pipeline. It will likely be blocked until you click through to give it permission to resources. This has to be done once, then subsequent runs will go through without manual intervention.

]]>
https://criticalhittech.com/2023/05/16/deploying-xamarin-and-maui-apps-from-azure-pipelines-to-google-play/feed/ 0 2069
Using Xamarin.UITest with Accessible Xamarin.Forms Apps https://criticalhittech.com/2021/07/29/using-xamarin-uitest-with-accessible-xamarin-forms-apps/ https://criticalhittech.com/2021/07/29/using-xamarin-uitest-with-accessible-xamarin-forms-apps/#respond Thu, 29 Jul 2021 21:47:00 +0000 https://criticalhittech.com/?p=1866 Continue reading "Using Xamarin.UITest with Accessible Xamarin.Forms Apps"]]> Millions of people around the world rely on assistive technology to computers and smartphones every day. While making sure your app is usable by as many people as possible seems like a good idea anyway, accessibility is becoming the law in a growing number of circumstances.

What’s the problem?

Xamarin.Forms provides a class of AutomationProperties that map to the native accessibility API on Android, iOS and Windows. These allow you to set the description of user interface elements so that they may be read aloud by a screen reader, a common form of assistive technology that is essential for many people with visual impairments.

Testing is also important, and Xamarin.UITest is a popular solution for automating UI-driven testing scenarios. Unfortunately, both Xamarin.UITest and AutomationProperties on Android use the same native ContentDescription property, which leads to apps that are either accessible or usable with Xamarin.UITest, but not both — and this is a longstanding pain point. Support for accessibility has been improving in Xamarin.Forms, particularly in Xamarin.Forms 5.0, however open issues remain.

Just setting AutomationId can cause accessibility issues with screen readers. We encountered one such issue when we were using Android’s TalkBack screen reader with a Label like the one below:

<Label AutomationId="WelcomeLabel"
       Text="Please set a login and password for this app."/>

When this Label comes into focus, the TalkBack screen reader announces it as “WelcomeLabel”. Only the AutomationId is read by the screen reader – the crucial Text is ignored! A screen reader user would not get to hear the instructions written in the Text property, so it would be difficult for them to understand and interact with this app’s content.

From an accessibility perspective, the fastest solution would be to remove the AutomationId completely and let the screen reader announce the rest of the element’s ContentDescription, including any AutomationProperties.Name or HelpText.

But since automated UI testing is required, developers still need to set the AutomationId to identify specific elements. Here is the other big conflict between UI testing and accessibility – the UI test will fail if it searches specifically for the AutomationId property of an element that also has AutomationProperties.

The sample UI test method below uses AppQuery.Property() to find the Entry element by its AutomationId. However because it also sets AutomationProperties.HelpText, it will fail to find it on Android:

MainPage.Xaml
<Entry AutomationId="UsernameEntryId" Text="{Binding Username}"
       AutomationProperties.IsInAccessibleTree="True"
       AutomationProperties.HelpText="Enter your name"/>

Tests.cs
// UI test fails - no element found
var entry = app.Query(c => c.All().Property("AutomationId",        "UsernameEntryId"));

Given this conflict, how can we balance the need for accessibility and UI testing without having a different build for each purpose or resorting to custom Android renderers?

Support for both UITest and Accessibility

We found a platform-independent way to set the AutomationId for UI tests while keeping it null in the during normal app execution so that screen readers can still read the Text and the AutomationProperties of the element. There are two parts to our solution: 1) a custom XAML markup extension and 2) a hidden button on the app startup page.

The markup extension has a flag that is set to true in the code-behind to signal switching to UI test mode. When this flag is set to true, the extension returns the Id string, otherwise it returns null. Here’s the code for the extension:

public class UITestModeExtension : IMarkupExtension
{
     public string Id { get; set; }
     public static bool IsInUiTestMode { get; set; } = false;    
     
     object IMarkupExtension.ProvideValue(IServiceProvider
      serviceProvider)
     {
        if (IsInUiTestMode)
            return Id;
        return null;
     }
}

Include the local namespace for the project in the XAML file, and then the extension can be used like the example below:

<Entry AutomationId="{ext:UITestMode Id=UsernameEntryId}"
       Text="{Binding Username}"
       AutomationProperties.IsInAccessibleTree="True"
       AutomationProperties.HelpText="Enter your name"/>

On the initial page of the app, have a hidden Button with a clicked event that sets IsInUiTestMode to true and creates a new instance of the page (code below). This will force the XAML elements to get recreated with the AutomationId now set, and all subsequent pages will also have the AutomationId set on their XAML elements.

<Grid RowDefinitions="1" ColumnDefinitions="1,*">
    <Button AutomationId="ToggleTestMode"
            TextColor="Transparent" BackgroundColor="Transparent"
            Clicked="ToggleTestModeButton_Clicked"
            AutomationProperties.IsInAccessibleTree="False"/>
</Grid>
private void ToggleTestModeButton_Clicked(
               object sender, EventArgs e)
{
    UITestModeExtension.IsInUiTestMode =
              !UITestModeExtension.IsInUiTestMode;
    Application.Current.MainPage = new MainPage();
}

Now in the UI test files, you can simulate Tap events on the Button to trigger the event that sets the AutomationId on the elements. After the Button is tapped, you can begin automated UI testing by querying for elements with an AutomationId.

An important thing to note here is to use the AppQuery.Marked() method to search for the element, and not AppQuery.Property() to access the AutomationId directly.

[Test]
public void CanSwitchAutomationIdMode()
{
    // 1: verify that entry is not found yet
    var entry = app.Query(c => c.All().Marked("UsernameEntryId"));
    Assert.AreEqual(entry.Count(), 0);
    // 2: tap the ToggleTestMode button
    app.Tap(c => c.Marked("ToggleTestMode"));
    // 3: wait for ToggleTestMode to reappear
    var button = app.WaitForElement(c =>
                 c.All().Marked("ToggleTestMode"));
    // 4: query for UsernameEntryId again
    var entrySecondQuery = app.Query(c =>
                           c.Marked("UsernameEntryId"));
    // 5: verify that UsernameEntryId is found
    Assert.AreEqual(entrySecondQuery.Count(), 1);

Normally, the code to toggle the button into test mode would be in a test setup method so it wouldn’t have to be repeated on every test.

Note that the “hidden” Button on our XAML page isn’t truly hidden. Setting IsVisible=”False” or otherwise making the Button truly not available in the visual tree means that the button can’t ever be tapped, even programmatically with UI Test. However a 1 pixel by 1 pixel button is good enough to be in the visual tree, available to UI Test, and in practice is not visible or able to be tapped by users.

To test accessibility, try your test device’s screen reader on the page with the Button not clicked (no AutomationId). Even though the page’s Xaml file sets the AutomationId with the custom extension, the screen reader should not read them until the Button is clicked. Keep in mind that the exact behavior of a screen reader varies depending on the platform and how it is used, and it is encouraged that you always perform manual tests for accessibility.

The app we used to demonstrate this solution is available here on GitHub: https://github.com/criticalhittech/UITestWithA11y.

We hope you find this guide useful as you consider accessibility features in your app!

]]>
https://criticalhittech.com/2021/07/29/using-xamarin-uitest-with-accessible-xamarin-forms-apps/feed/ 0 1866
Setting up your Xamarin.Forms application as a sharing target https://criticalhittech.com/2021/03/25/setting-up-your-xamarin-forms-application-as-a-sharing-target/ https://criticalhittech.com/2021/03/25/setting-up-your-xamarin-forms-application-as-a-sharing-target/#respond Thu, 25 Mar 2021 15:27:00 +0000 https://criticalhittech.com/?p=1787 Continue reading "Setting up your Xamarin.Forms application as a sharing target"]]> Using Xamarin.Forms to develop mobile applications is particularly desirable because most of the UI and interaction logic for iOS and Android can be shared in a single common project. However, there are instances where code cannot be shared and has to be implemented in the platform specific projects.

One scenario that we will be discussing in this blog is setting up an application as a sharing target. There are a hand full of items that a user could share to an application from a device, for example images, text and files of various types. This post will walkthrough a sample for sharing url links from a browser to a Xamarin application, while discussing other sharing options.

Here is the documentation on how to setup an Android application as a sharing target and the sample below uses that as a reference. However, there aren’t many resources online on how to navigate back to the original application after the sharing is complete which the sample below will get into.

For Xamarin.iOS on the other hand, there are tools and templates available for setting up an iOS extension project. An IOS extension is a small standalone application for the sole purpose of displaying the sharing UI on the host application. The host application is the application that does the sharing to the target application and in the sample below the host application would be a browser application.

Below I will walk through a step by step example for setting up an Android and iOS application as a target for sharing url links.

Setting up your Xamarin.Android application as a sharing target

1.) Add an intent filter to the AndroidManifest.xml file like below.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.companyname.sharelinksamplexamandroid">
  <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28" />
    <application android:label="ShareLinkSampleXamAndroid.Android" android:theme="@style/MainTheme">
       <activity android:name=".MainActivity" >
          <intent-filter>
             <action android:name="android.intent.action.SEND" />
             <category android:name="android.intent.category.DEFAULT" />
             <data android:mimeType="text/plain" />
          <intent-filter/>
       <activity />
     <application/>
  <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<manifest/>

You can add multiple “intent-filter” tags for each media type that you want to allow sharing to your application as shown here. For this example, we’ve set up one intent-filter with the android:mimetype set to “text/plain” for sharing links.

2.) Set the name attribute on the activity that will receive the callback when a user clicks the share icon.

In the manifest above, the android:name value on the activity tag corresponds to the activity that will receive the callback. For Xamarin.Forms applications, the activity has to be the main launcher, if not the application will crash. And the name has to be preceded by the application’s package name like below

3.) Display and handle the url that the user wants to share to the application.

In the MainActivity.OnCreate method, first check if the Intent.Action and Intent.Type values corresponds to the values set in the AndroidManifest. If they match that means an application or browser has requested to share a url link to our application and now we can display the UI for handling this. In the sample below, a Dialog is displayed with the url and a text input for the user to enter a description for the url.

4.) And when the user is done, FinishAndRemoveTask() is called to kill the sharing request task and FinishAffinity() navigates the user back to the application that did the sharing.

     protected override void OnCreate(Bundle savedInstanceState)
     {
        TabLayoutResource = Resource.Layout.Tabbar;
        ToolbarResource = Resource.Layout.Toolbar;

        base.OnCreate(savedInstanceState);
        Xamarin.Essentials.Platform.Init(this, savedInstanceState);
        global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
        LoadApplication(new App());

        if (Intent.ActionSend.Equals(Intent.Action) && 
            Intent.Type != null &&
            "text/plain".Equals(Intent.Type))
          {
             handleSendUrl();
          }
    }

    private void handleSendUrl()
    {
       var view = new LinearLayout(this) { Orientation = Orientation.Vertical };
       var url = Intent.GetStringExtra(Intent.ExtraText);

       var urlTextView = new TextView(this) { Gravity = GravityFlags.Center };
       urlTextView.Text = url;

       view.AddView(urlTextView);
       var description = new EditText(this) { Gravity = GravityFlags.Top };
       view.AddView(description);

       new AlertDialog.Builder(this)
                .SetTitle("Save a URL Link")
                .SetMessage("Type a description for your link")
                .SetView(view)
                .SetPositiveButton("Add", (dialog, whichButton) =>
                {
                    var desc = description.Text;
                    //Save off the url and description here
                    //Remove dialog and navigate back to app or browser that shared                 
                    //the link
                    FinishAndRemoveTask();
                    FinishAffinity();
                })
                .Show();
   }

Setting up your Xamarin.iOS application as a sharing target

1.) Add a new iOS > Extension > Share Extension project like below. I did try the Share Links Extension template but I could not get it to run on my simulator with Xamarin.Forms version 5.0 on VSMac version 8.9.2.

The template should contain the following files:

  • Info.plist
  • MainInterface.storyboard
  • ShareViewController

2.) To allow sharing of only url links to your application, modify the NSExtensionAttributes dictionary in the Info.plist file of the Extension project to the following:

Also notice that the first part of bundle identifier “com.companyname.ShareLinkSampleXamIOS” matches the bundle identifier of the iOS project. They have to match for the extension to work.

3.) Receive and save off the url and description shared by the user.

In the ShareViewController.DidSelectPost method enumerate the shared items and get the url as shown in the code below:

    public override void DidSelectPost()
    {
       var description = "";
       var url = "";

       foreach (var extensionItem in ExtensionContext.InputItems)
       {
          if (extensionItem.Attachments != null)
          {
             foreach (var attachment in extensionItem.Attachments)
             {
                if (attachment.HasItemConformingTo(UTType.URL))
                {
                   attachment.LoadItem(UTType.URL, null, (data, error) =>
                   {
                     var nsUrl = data as NSUrl;
                     url = nsUrl.AbsoluteString;
                     WriteToDebugFile($"URL - {url}");
                     //Save  off the url and description here
                   });
                }
             }
          }
          if(!string.IsNullOrWhiteSpace(extensionItem.AttributedContentText.Value))
          {
             description = extensionItem.AttributedContentText.Value;
             WriteToDebugFile($"URL description - {description}");
          }
       }
       ExtensionContext.CompleteRequest(new NSExtensionItem[0], null);
   }

4.) Debugging the iOS extension can be a little tricky as the debugger does not get attached to the extension. Instead I used the approach of writing to the filesystem of the extension application as shown below:

   private void WriteToDebugFile(string dbgText)
   {
      var documents = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
      var filename = Path.Combine(documents, "Debug.txt");

      if (!File.Exists(filename))
      {
         File.WriteAllText(filename, $"\n{DateTime.Now} - {dbgText}");
      }
      else
      {
         File.AppendAllText(filename, $"\n{DateTime.Now} - {dbgText}");
      }
   }

Because an extension is a standalone application, it has its own application folder separate from the main application folder. To navigate to the folder, start by opening the Library folder on your MacBook. From there, navigate to the
Developer > CoreSimulator > Devices folder and you should see a list of all your simulators. And from there, navigate to the PluginKitPlugin folder and locate your application folder.

The full code samples can be found below:

Android : https://github.com/criticalhittech/ShareLinkSampleXamAndroid
iOS: https://github.com/criticalhittech/ShareLinkSampleXamIOS

]]>
https://criticalhittech.com/2021/03/25/setting-up-your-xamarin-forms-application-as-a-sharing-target/feed/ 0 1787
Xamarin.Forms BackgroundColor, TextColor, and Dark Mode https://criticalhittech.com/2021/02/18/xamarin-forms-backgroundcolor-textcolor-and-dark-mode/ https://criticalhittech.com/2021/02/18/xamarin-forms-backgroundcolor-textcolor-and-dark-mode/#respond Thu, 18 Feb 2021 23:15:48 +0000 https://criticalhittech.com/?p=1707 Continue reading "Xamarin.Forms BackgroundColor, TextColor, and Dark Mode"]]> We recently undertook updating an older Xamarin.Forms app to include Dark Mode support on iOS. Newer versions of Xamarin.Forms makes it pretty easy to set up a good framework. There are some useful blog posts here and here on how to set up a framework in your app, and some very useful Microsoft documentation here.

But then we started to run into bugs, one by one. Bits of the UI just weren’t responding as we expected to Dark Mode. Thus started a journey of discovery to methodically understand how background and text colors work. Hopefully you will find this helpful in your Dark Mode efforts as well.

We’re only looking in detail at iOS, which has made Dark Mode opt-out. We’re also focusing on issues that have to do with text. There are other important issues, like images, but that’s for another post.

What does Dark Mode do?

From a high level, switching between light and dark mode simply causes some system managed colors to change. In Light Mode, the default system background is white and text is black, and vice versa for Dark Mode (not necessarily pure white and black, but close). But this is at the iOS level. Xamarin.Forms sits between your app and iOS, and Xamarin.Forms sets some colors on its own. This means that a Xamarin.Forms app will see default behavior that doesn’t exactly match the iOS platform.

Brief background on BackgroundColor

Before getting into details, here’s a little context about BackgroundColor and how it usually works. This shouldn’t be a surprise to Xamarin.Forms developers.

Everything that takes up space on the screen has a BackgroundColor. For most controls and containers, it’s transparent, letting its parent’s color through. Consider:

<StackLayout BackgroundColor="HotPink" x:Name="S1">
  <StackLayout x:Name="S2">
    <Grid>
      <Label Text="Hello there"/>
      ...

The text will appear with a BackgroundColor of HotPink because the StackLayout S2 and Grid default to transparent BackgroundColor, letting the HotPink from S1 shine through. This “nesting” principle is pretty intuitive, and generally works pretty well.

Where things get interesting

Common sources of Dark Mode app bugs are where there are Xamarin.Forms defaults that aren’t compatible with iOS when in Dark Mode, and times when Xamarin.Forms doesn’t obey the “nesting” principle for BackgroundColor.

An important Xamarin.Forms default is Page, where BackgroundColor defaults to White, regardless of Light vs Dark Mode. There are others, which we’ll get to later.

There is no Xamarin.Forms default for TextColor on Label, so it uses the iOS defined color. The iOS color changes between themes. For example, let’s look at an example from a page that has some unexpected Dark Mode behavior:

<CollectionView x:Name="ItemsListView" ItemsSource="{Binding Items}">
  <CollectionView.Header>
    <SearchBar Grid.Row="1"></SearchBar>
  </CollectionView.Header>
  <CollectionView.ItemTemplate>
    <DataTemplate>
      <StackLayout Padding="10" x:DataType="model:Item">
        <Label Text="{Binding Text}" FontSize="16" />
        <Label Text="{Binding Description}" FontSize="13" />
      </StackLayout>
    </DataTemplate>
  </CollectionView.ItemTemplate>
</CollectionView>

Now compare how they look in Light versus Dark Mode:

CollectionView & SearchBar, Light Mode

CollectionView & SearchBar, Dark Mode

Because Page is White by default, and CollectionView doesn’t override it, the whole page remains White in both. Label.TextColor in the collection’s ItemTemplate changes based on the Theme, as does the BackgroundColor of the SearchBar. As you can see, this makes the list unreadable, and the search bar has a distractingly mismatched background.

If your app design uses white backgrounds and black text, you might be relying on some of these defaults without realizing it — that’s what happened to us.

BackgroundColor

As already noted, Page defaults to White. However Frame, ListView, and ListView.GroupHeaderTemplate do not display their parent’s background color. So if you want a Frame to have the same background color as its parent, you have to explicitly set it. The default BackgroundColor for these is typically the iOS default background, but factors like Material design can change that.

Then there are the controls that contain text. Many of these have a transparent default BackgroundColor, but some do not. As a rule of thumb, most input controls do not have a transparent BackgroundColor, typically they use the iOS default background color. This includes Entry, Editor, SearchBar, and the Picker controls. This explains the SearchBar example above — it’s embedded inside the ListView, but its BackgroundColor is the system default, which responds to theme changes.

TextColor

Luckily, understanding the default color for text is a lot easier — it almost always defaults to the system-defined color, and responds to changes in system theme.

However there are two that don’t quite work that way: TextCell, and Span inside Label.FormattedText. When these are first rendered on the screen, they will pick up the system default colors, just as you’d expect. However depending on the structure of the page, they might or might not change color if the system theme changes. So even everything is fine when the app first launches, it could look wrong when the theme changes.

Setting color where it’s needed

In general, you need to style elements so they respond to theme changes when they wouldn’t otherwise (like Page), or so they respond in a way that matches your desired colors rather than iOS defaults. You can do this with colors or styles on the elements directly, or through implicit styles.

Most containers/controls display a their parent’s background color by default, and have text color that changes automatically with the theme. This means that a lot of colors do not have to be specified because the right thing just happens.

However these are exceptions which need special attention in applying styles (for background and/or text colors):

  • BackgroundColor
    • Page
    • Frame
    • ListView
    • ListView.GoupHeaderTemplate
    • Entry
    • Editor
    • SearchBar
    • Pickers
  • TextColor

Using XamRight to help

In order to thoroughly check our own app, in XamRight 2.50 we introduced a preview of checking for potential Dark Mode issues. This warns you about everywhere that there might be a TextColor/BackgroundColor combination where there is a mismatch between how the two colors respond (or don’t respond) to theme changes. We tested it out on the open source Xappy app, and found Dark Mode readability problems lurking in some out-of-the way UI:

Xappy Light Mode

Xappy Dark Mode

Most of the page looks great, but the bottom toolbar doesn’t look quite right. XamRight was able to point this out on this page:

If you’re adjusting to Dark Mode, try out XamRight — hopefully it’ll make it easier for you to find places in your app that still need work.

]]>
https://criticalhittech.com/2021/02/18/xamarin-forms-backgroundcolor-textcolor-and-dark-mode/feed/ 0 1707
XamRight 2.30 Release for Visual Studio https://criticalhittech.com/2020/12/17/xamright-2-30-release-for-visual-studio/ https://criticalhittech.com/2020/12/17/xamright-2-30-release-for-visual-studio/#respond Fri, 18 Dec 2020 00:39:28 +0000 https://criticalhittech.com/?p=1662 Continue reading "XamRight 2.30 Release for Visual Studio"]]> We thrilled to announce the release of XamRight 2.30. This release continues to improve its powerful XAML static analysis capabilities, and introduces features to streamline your XAML development.

This release is available today for Visual Studio 2017 and 2019, and will be released for Visual Studio for Mac within a few short days.

Binding Converters

When XamRight detects that you are trying to use an undefined Binding Converter, it gives you the option to create one right there.

You can either look up converters you already have in your project, write a new one from an empty template, or import a converter from libraries of Binding Converters on GitHub.

Importing from GitHub allows you to avoid reinventing the wheel — there are a lot of useful converters already written. This gives you the option to import the source rather than add a nuget dependency — giving you the freedom to customize rather than write from scratch.

Right out of the box, XamRight let’s you import from two great open source libraries of converters:

CrossGeeks: CrossGeeks/UsefulConvertersSample: Xamarin Forms useful converters list. (github.com)

James Montemagno Xamarin.Forms Toolkit: jamesmontemagno/xamarin.forms-toolkit: Toolkit for Xamarin.Forms (Controls, Behaviors, and Converters) (github.com)

To see a demo showing this in action, click here.

Tap Gesture Recognizers

Reduce the amount of boilerplate you need to type to insert a TapGestureRecognizer. XamRight will insert the appropriate, context-aware, nodes for you to start customizing.

Custom View Model Properties

XamRight comes prepackaged with a number of templates it can use to automatically inject C# property definitions into view model classes. If none of those fit your situation, you can define reusable templates for the property.

]]>
https://criticalhittech.com/2020/12/17/xamright-2-30-release-for-visual-studio/feed/ 0 1662
XamRight 2: Visual Studio for Mac, Triggers, and more https://criticalhittech.com/2020/05/21/xamright-2-visual-studio-for-mac-triggers-and-more/ https://criticalhittech.com/2020/05/21/xamright-2-visual-studio-for-mac-triggers-and-more/#respond Fri, 22 May 2020 00:05:48 +0000 https://criticalhittech.com/?p=1517 Continue reading "XamRight 2: Visual Studio for Mac, Triggers, and more"]]> It’s been a while since we’ve posted anything, but rest assured, we’ve been busy listening to feedback from users and improving XamRight. In the last few months, we’ve made XamRight faster, more reliable, with more accurate analysis. And that’s just the behind-the-scenes stuff. There are several visible features to talk about, and for this post we talk about two, shown in the demo below:

XamRight for Visual Studio for Mac

First of all, XamRight now runs as a Visual Studio for Mac extension, bringing all of the Binding analysis, Xaml checking, autocomplete, code editing assists, and more, that the Visual Studio (for Windows) version has. It is currently available in the Visual Studio for Mac Extension Gallery in the Beta Channel.

The other feature highlighted here is support for Triggers. Triggers are a great way to declaratively express how Xaml properties react to changes in Binding properties or other elements. There are some great blog tutorials about Triggers, for instance https://xamgirl.com/understanding-triggers-in-xamarin-forms/ and https://askxammy.com/getting-started-with-triggers-in-xamarin-forms/, with others just a quick search away. This demo shows how Data Triggers, Multi Triggers, and Property Triggers can be used in a realistic situation.

One thing about Triggers – they are a bit wordy. XamRight helps you use Triggers more easily by generating the correct structure for you, which will vary based on context. Then it’s up to you to fill in the blanks — adding in the specific behavior you want to see.

When filling in the details of Triggers, XamRight error checking steps in to help. Skip ahead to 20 seconds into the video to see how XamRight Binding checker indicates that the Binding property specified by the DataTrigger doesn’t exist on the view model class, and then gives the developer an easy way to inject a new C# view model property.

There are more exciting features we’ll be sharing soon!

XamRight is available for trial from both the Visual Studio Marketplace (2017 and 2019) and Visual Studio for Mac Extension Gallery.

]]>
https://criticalhittech.com/2020/05/21/xamright-2-visual-studio-for-mac-triggers-and-more/feed/ 0 1517
Editing and Maintaining Grids with XamRight https://criticalhittech.com/2019/12/16/editing-and-maintaining-grids-with-xamright/ https://criticalhittech.com/2019/12/16/editing-and-maintaining-grids-with-xamright/#respond Tue, 17 Dec 2019 00:33:25 +0000 https://criticalhittech.com/?p=1447 Grids are a popular layout, giving you lots of flexibility and good layout performance. However they can get to be difficult to work with as they become increasingly complex. Take a look at this quick demo showing a few of the features of XamRight that make it easier to work with Grid layouts in Xaml.

Demonstrating XamRight features for Grids

]]>
https://criticalhittech.com/2019/12/16/editing-and-maintaining-grids-with-xamright/feed/ 0 1447
ICYMI: XamRight on the Xamarin Show https://criticalhittech.com/2019/12/03/icymi-xamright-on-the-xamarin-show/ https://criticalhittech.com/2019/12/03/icymi-xamright-on-the-xamarin-show/#respond Tue, 03 Dec 2019 21:19:11 +0000 https://criticalhittech.com/?p=1440 The episode aired a couple of months back. It was a great conversation about how to use XamRight to make Xamarin development in Visual Studio easier and faster.

]]>
https://criticalhittech.com/2019/12/03/icymi-xamright-on-the-xamarin-show/feed/ 0 1440