Runar Ovesen Hjerpbakk

Science-based software development

iOS

Two Xamarin.iOS build errors

Iā€™m creating a new Xamarin Forms app using a PCL-project for shared code and an iOS project for the iOS specific details. After a short hiatus, I upgraded to Visual Studio for Mac version 7.0.1 for a nice morning of coding. No such luck, the iOS project would not build.

Read More

Make the macOS firewall to permanently allow iOS apps running in the simulator

macOS has an awesome firewall, however the default setting is very harsh for us iOS developers.

Read More

Xamarin.iOS app crash on startup in simulator

I updated to Xamarin Studio 6 this morning. A beautiful update with dark mode, full Roslyn support and prettier icons. And it prevented my Xamarin.iOS app from starting in the simulator.

Read More

Workday Countdown - A Status Board panel

Workday Countdown is a countdown panel for Panic's Status Board 2 application for iOS. Different from the stock Countdown panel, Workday Countdown filters out weekends and public holidays. This provides a more realistic countdown in a work setting where people are not expected to come in on weekends.

View the source on GitHub.

Read More

Tiling a sprite texture in SpriteKit

I'm writing my next game, Icarus - Escape from Crete, using Xamarin iOS together with SpriteKit. The combination works great and SpriteKit turns out to be a well thought out API. My only gripe so far is that I haven't found an existing way for tiling a sprite texture, that is fill the entire sprite using a smaller texture.

The grass below is just a small image, repeated to fill the entire green meadow. Icarus in a green meadow


The grass is created from this simple tile Small grass texture


using an extension method on SKSpriteNode

/// <summary>
/// Creates a tiled texture and applies it to the <see cref="SKSpriteNode"/>.
/// </summary>
/// <param name="spriteNode">The <see cref="SKSpriteNode"/> to which the texture is applied.</param>
/// <param name="texture">The texture used as tiles.</param>
/// <param name="coverageSize">The size of the finished tiled texture.</param>
public static void TileSprite(this SKSpriteNode spriteNode, UIImage texture, CGSize coverageSize) {
  var textureSize = new CGRect(CGPoint.Empty, texture.Size);

  UIGraphics.BeginImageContext(coverageSize);
  var context = UIGraphics.GetCurrentContext();
  context.DrawTiledImage(textureSize, texture.CGImage);
  var tiledBackground = UIGraphics.GetImageFromCurrentImageContext();
  UIGraphics.EndImageContext();

  spriteNode.Texture = SKTexture.FromImage(tiledBackground.CGImage);
  spriteNode.Size = coverageSize;
}


Using CoreGraphics, an image of the proper size is created and the texture is tiled. Next the image is rendered and a SKTexture is created from the result.

Here's the example from Icarus:

var grass = new SKSpriteNode();
grass.TileSprite(UIImage.FromFile("grass"), new CGSize(Device.Width, GrassHeight));

This method has two disadvantages though.

  1. It's slow. Create the needed nodes during game loading, not during gameplay.
  2. The resulting image is flipped. Remedy this by either using a flipped image as the tile, or flip the Y-axis on the SKSpriteNode after the texture is applied: grass.YScale = -1f; I use the former.

Even with the disadvantages, the method was useful in Icarus. Maybe it's useful for you too šŸ˜ƒ

Read More

Gradient Colors on iOS

I needed a way to get a color between two colors given a ratio while working on the 1.1 version of Golden Ratio Calculator. I use it to show a color between blue and gold, then gold and silver, and lastly between silver and blue.

public static UIColor ColorForRatio(float[] startColor, float[] endColor, float colorRatio) {
 return UIColor.FromRGB(
  startColor[0] + (endColor[0] - startColor[0]) * colorRatio, 
  startColor[1] + (endColor[1] - startColor[1]) * colorRatio, 
  startColor[2] + (endColor[2] - startColor[2]) * colorRatio);
}
Color Ratio Example

The start and end colors are represented as arrays of RGB ratios, but this is easy to work with.

Either get the RGB-ratios from a UIColor:

var startColor = new nfloat[4];
UIColor.White.GetRGBA(out startColor[1], out startColor[2], out startColor[2], out startColor[3]);

Or create the array directly:

var upperAtmosphereColor = new nfloat[] { 32/255f, 79/255f, 205/255f };

Read More

ERROR ITMS-9000: Invalid Code Signing Entitlements

Version 1.6 of Book Scanner now supports 64bit and has an iOS 8 today widget extension. While submitting this version to the App Store, I was presented with this dialog. ERROR ITMS-9000: Invalid Code Signing Entitlements

Invalid Code Signing Entitlements. Your application bundle's signature contains code signing entitlements that are not supported on iOS.

I'm using the Unified Xamarin API and I was certain that all the entitlements were correct.

After a round of Googling', I've found post on the Xamarin Forums. It mentions that this error will be fixed in a newer version of Xamarin iOS. I was using version 5.5.4 of Xamarin Studio and 8.4.0.43 of Xamarin iOS.

Before the fix is released, you can use updated MSBuild files for Xamarin iOS. Just unzip that linked file in /Library/Frameworks/Mono.framework/External/xbuild/Xamarin/

Read More

From UIAlertView to UIAlertController using Xamarin and async / await

UIAlertView has been deprecated by Apple from iOS8. From now on, UIAlertController is the way to go. UIAlertController is surely an improvement, but given the asynchronous nature of displaying alerts to the user, I wanted to use the API together with async and await.

Below is a screenshot of what I wanted to accomplish: Customer feedback sheet

A simple menu with two options and a Cancel-button.

UIAlertController lets you add multiple UIAlertActions, each with its own handler which is just a normal Action. I want to present the menu to the user and wait for her to select one of the items.

By using a TaskCompletionSource, I can accomplish this using async and await.

public static class CustomerFeelingSheet {
  public static Task<CustomerFeeling> ShowRatingDialogAsync(UIViewController parent) {
    var taskCompletionSource = new TaskCompletionSource<CustomerFeeling>();

    var alert = UIAlertController.Create(
      "howDoYouFeel".T(), null, UIAlertControllerStyle.ActionSheet);

    alert.AddAction(UIAlertAction.Create(
      "likeIt".T(), UIAlertActionStyle.Default,
      a => taskCompletionSource.SetResult(CustomerFeeling.LikeIt)));
    
    alert.AddAction(UIAlertAction.Create(
      "couldBeBetter".T(), UIAlertActionStyle.Default,
      a => taskCompletionSource.SetResult(CustomerFeeling.CouldBeBetter)));
    
    alert.AddAction(UIAlertAction.Create(
      "cancel".T(), UIAlertActionStyle.Cancel,
      a => taskCompletionSource.SetResult(CustomerFeeling.DontCare)));

    parent.PresentViewController(alert, true, null);
    return taskCompletionSource.Task;
  }
}

The TaskCompletionSource can be used to map an external asynchronous operation onto a normal C# Task. We can then use this task as we would any other.

In this case, the result of this task is the Enum CustomerFeeling with values corresponding to the users happiness. Thus, ShowRatingDialogAsync can be used like this:

var customerFeeling = await CustomerFeelingSheet.ShowRatingDialogAsync(parentVC);
switch(customerFeeling) {
  case CustomerFeeling.LikeIt:
    // "I like it!" was chosen 
    break;
  case CustomerFeeling.CouldBeBetter:
    // "It could be better..." was chosen
    break;
  default:
    // "Cancel" was chosen
    return;
}

The choice of the user can be awaited and UIAlertController now fits in perfectly with the rest of the C# code.

Read More

ERROR ITMS-9000: Invalid Image Path

I just submitted version 1.5 of Book Scanner to the App Store, but this time I needed two tries.

Book Scanner now fully supports iOS8 and the larger iPhones, and I've also update the app's icons. I use asset catalogs and had dutifully added icons in all the slots. Then I started uploading the app using Application Loader. After a while, this error message appeared: ERROR ITMS-9000: Invalid Image Path

ERROR ITMS-9000: "Invalid Image Path - No image found at the path referenced under key 'CFBundleIcons': 'AppIcons120x120'"

After a little trial and error, it turns out that the CarPlay icon was the culprit. I removed the CarPlay icon from the asset catalog and the upload completed successfully.

No CarPlay Icon

And I will update Book Scanner to 64bit soon...

Read More

New features in FermiContainer 1.1

FermiContainer gains features, but while doing so becomes even more simple. How is this possible? Let me tell you:

Automatic resolving of constructor arguments

Through constructor injection, the dependencies known to the container are automatically resolved. No attributes or XML configuration are needed.

[Test]
public void Register_EvenMoreComplexClass_CanBeResolved() {
  m_fermiContainer.Register<IEvenMoreComplex, EvenMoreComplex>();
  m_fermiContainer.Register<ICalculator, Calculator>();
  m_fermiContainer.Register<IComplex, ComplexClass>();
  m_fermiContainer.Register<ClassWithoutInterface>();

  var complexInstance = m_fermiContainer.Resolve<IEvenMoreComplex>();

  IsInstanceOf<IEvenMoreComplex>(complexInstance);
}

public interface ICalculator {}

public class Calculator : ICalculator {}

public interface IComplex {}

public class ComplexClass : IComplex {
  public ComplexClass(ICalculator calculator) {}
}

public interface IEvenMoreComplex {}

public class EvenMoreComplex : IEvenMoreComplex {
  public EvenMoreComplex(
    IComplex complex, I
    Calculator calculator, 
    ClassWithoutInterface classWithoutInterface) {}
}

public class ClassWithoutInterface {}>

Default container instance

var instance = FermiContainer.DefaultInstance;

IsInstanceOf<IFermiContainer>(instance);
Assert.AreSame(instance, FermiContainer.DefaultInstance);

Easier to extend

The Services dictionary is now protected so FermiContainer is easily extendable.

Better performance

C# expressions makes FermiContainer very performant.

Available as source through NuGet

PM> Install-Package FermiContainer.Sources

Read More

Introducing FermiContainer - an IoC container for the rest of us

What the world needs most is more IoC containers in the .Net space.

So I created FermiContianer, the simples IoC container imaginable.

It supports registering implementations of interface using either a default constructor or a factory method.

IFermiContainer fermiContainer = new FermiContainer();

fermiContainer.Register<ICalculator, Calculator>();
fermiContainer.Register<ClassWithOutAnInterface>();

Resolve gives you a new instance each time.

var calculator = fermiContainer.Resolve<ICalculator>();

Assert.IsInstanceOf<Calculator>(calculator);

var calculator2 = fermiContainer.Resolve<ICalculator>();

Assert.AreNotSame(calculator, calculator2);

Singleton will return the same instance.

var calculator = fermiContainer.Singleton<ICalculator>();

var calculator2 = fermiContainer.Singleton<ICalculator>();

Assert.AreSame(calculator, calculator2);

That's it! Available through NuGet for for .Net 4.0 or later, Xamarin.iOS, Xamarin.Mac, Xamarin.Android, Windows 8, Windows Phone 8, Windows Store apps and Silverlight 5. The source lives on GitHub.

PM> Install-Package FermiContainer

If FermiContainer ever becomes too simple for your needs, I recommend LightInject.

Read More

Replacing Launch Images with Storyboards using Xamarin.iOS

As of iOS 8 you can now use storyboards instead of images for your app's launch image. This is convenient, as you only need to create one storyboard instead of multiple launch images (one for each device form factor). This post by Ole Begemann outlines the procedure for a regular iOS app, I'll now show you how it's done using Xarmarin.iOS.

Instructions

  1. Create an empty storyboard in Xamarin Studio and name it LaunchScreen.storyboard.
  2. Open Options for your Xamarin.iOS project and set the newly created storyboard as the launch image.
  3. Edit your storyboard using Xamarin iOS Designer or Xcode Interface Builder. The iOS Human Interface Guidelines specifies that:

Design a launch image that is identical to the first screen of the app, except for: [1] Text. ā€¦ [2] UI elements that might change.

After you're satisfied with your design, remember to tick the Is Initial View Controller checkbox. Without it, your View Controller will not be loaded and you're stuck with a black only launch image.

Note that storyboard launch images do not work in the iOS Simulator at the moment, so be sure to test it on a real device.

Caveat

After replacing your launch images with a storyboard, your app will appear in full size on all devices. This includes the iPad, even if you've created an iPhone only app. If your app is unusable on the iPad in this state, I would hold off until / if this bug is fixed.

Book Scanner will use a storyboard launch images from version 1.5, which is under development.

Read More

Xamarin.Forms - App Store rejection

My new app Personal Trainer Worksheet - Time Tracking for Professional PTs is written using Xamarin.Forms and is currently available on the App Store. It's been a pleasure developing it using the Xamarin tools and I decided to release a iOS version first. However the App Store did not quite agree this time...

Application Loader

While submitting the App using Application Loader, it complained that the API usage info to be sent to Apple was too big, and that the analysis would continue on Apples servers. Okay, I thought and submitted anyway.

Moments later, this mail arrived in my inbox:

We have discovered one or more issues with your recent delivery for "Personal Trainer Worksheet - Time Tracking for Professional PTs". To process your delivery, the following issues must be corrected:

Non-public API usage:

The app references non-public selectors in PersonalTraineriOS: artwork, command, finished, initWithSendPort:receivePort:components:, isContainer, isNegative, playbackProgress, playbackRate, rating, removeTarget:, setArtwork:, setContainer:, setLocalizedTitle:, setPlayable:, setPlaybackProgress:

That was quite a mouthful.

Enable linking for SDK assemblies

The app doesn't use many third party dependencies, so I was quite certain the error was on my part.

The Monotouch linker can remove unused classes from your Xamarin iOS App, thus decreasing its size. The "too big" error message in Application Loader was actually a good hint that the linker had not run.

Sure enough, my project settings were set to Don't link. After changing it to Link SDK assemblies only, the API usage analysis ran successfully and the app was approved.

I don't know why the non-linked binary was rejected, but this thread on the Xamarin Forums shows that I'm not alone.

Read More

Xamarin.Forms 24 hour TimePicker on iOS

I'm utilizing Xamarin.Forms in my next app to more easily support both iOS, Android and Windows Phone using the (mostly) same code base. It's relatively new however, and some use cases are not yet supported using Xamarin's supplied controls.

The Problem

My problem today was showing a TimePicker using a 24 hour time format, regardless of the users selected locale. The TimePicker normally respects the users preference, but I'm using the control to select a range of time, not a point in time.

TimePicker's Format property only affects the string showing the selected time, not the selection itself.

Forcing 24 hours on iOS

Since my next app will first be released on iOS (naturally), I tackled the problem there first. My solution was to create a custom renderer which forces the underlying UIDatePicker to always use a local with a 24 hour time format. In this case I chose Norwegian, but any 24h locale will do. The picture illustrates what I wanted to accomplish. The picture illustrates what I wanted to accomplish.

using MonoTouch.Foundation;
using MonoTouch.UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using PersonalTrainer.iOS.View.Controls;

[assembly: ExportRenderer (typeof (TimePicker), typeof (TimePicker24HRenderer))]
namespace YourNamespace.iOS.View.Controls {
  public class TimePicker24HRenderer : TimePickerRenderer {
    protected override void OnElementChanged(ElementChangedEventArgs<TimePicker> e) {
      base.OnElementChanged(e);
      var timePicker = (UIDatePicker)Control.InputView;
      timePicker.Locale = new NSLocale("no_nb");
    }
  }
}

To use the code yourself, just drop the class into your iOS project and use the TimePicker normally in your shared project or PCL.

Read More

Xamarin.Forms and iOS Simulator Scrolling

Here are a couple of Xamarin quick tips i have found useful the last couple of days.

iOS simulator refuses to scroll

If your iOS simulator refuses to scroll your ListView or TableView, try restarting it. The simulator sometimes locks up and disables scrolling for some reason. This has only happened during my Xamarin.Forms development, but I have no clue as of the source.

Open another instance of Xamarin Studio

To open another instance of Xamarin Studio on OS X, use the following command in the Terminal.app:

open -n "/Applications/Xamarin Studio.app"

To open another instance of Xamarin Studio on OS X, use the following command in the Terminal.app:

open -n "/Applications/Xamarin Studio.app"

Given that Xamarin Studio is in its default location. Sometimes Unix can be useful, who knew? šŸ˜¬

Read More

Book Scanner promotional video

A promotional video for Book Scanner is now live on YouTube. It got some really inspirational music and amazing transitions. Check it out!

Read More

Book Scanner (iOS)

Scan a book

Buy it if you want

View all scanned books


My new app Book Scanner, also known as Book Barcode Scanner is now available worldwide on the App Store.

Book Scanner scans ISBN-barcodes and finds the books on iBooks. The app remembers your scanned books and you can buy them on iBooks at your convenience. Scanning book barcodes is faster than a manual search and the it's very useful in bookstores and other places with a lot of books.

Book Scanner is available free on the App Store and is of course written in C# using the Xamarin stack. I've learned a lot while writing this app, and I will share some of it here on this blog.

Read More

iOS Simulator scaling on a retina display

tl;dr

If the iOS Simulator scaling is set to 75% or 100% on a non-retina display, scale it to 50% before moving it to a retina display.

Symptom

One of the biggest advantages of a Retina MacBook Pro is that the iOS Simulator can run at 100% resolution and you get a good feel for what your app will look like on the real device. Running the simulator on an external display, you often need to scale down the window to 75% or 50% in order to view the whole thing.

100 scaling quite large

If the simulator scaling is set to 100% or 75% on a non-retina display, it will retain its seemingly large size when moved to the retina display.

Double retina, not exactly useful

Solution

Before moving the simulator to a retina display, set the scaling to 50%. The simulator will detect the retina display and set its scaling to 100%.

Scale

Exactly as we want.

Perfect!

Cause

The iOS Simulator only seems to auto scale if its scaling is set to 50% on a non-retina display.

Read More