Corrado's Blog 2.0

Online thoughts of a technology funatic

Fixing SDWebImage issue on Xamarin.iOS

Loading an image into an ImageView control using Xamarin.iOS is a straightforward process:

  • Add a ImageView to a ViewController and give it a name (e.g: MyImage)
  • Add an image to Resources folder (e.g Users.png) and be sure that related Build Action is set to BundleResource.
  • And add this code:
        public override async void ViewDidLoad() { base.ViewDidLoad(); MyImage.Image=UIImage.FromBundle("Users.png"); }

      And you’re done, as alternative you can also use UIImage.FromFile, in this case the call is asynchronous and doesn’t use caching, while former is synchronous and does caching.

      Ok, but what if I want to show an image from a web url? things gets more complicated since you have to do the entire downloading process manually, something like:

      public async Task<UIImage> FromUrl(string imageUrl) { var httpClient = new HttpClient(); var contents = await httpClient.GetByteArrayAsync(imageUrl); return UIImage.LoadFromData(NSData.FromArray(contents)); }

      And use it this way:

      MyImage.Image = await this.FromUrl("http://thechromenews.com/wp-content/uploads/2015/11/Apple-Logo-4.png");

      Cool, but what if I want to use caching, show a placeholder or fire some code when downloading completes? well, that’s more code to write and since this is a quite common task you’ll be happy to know that there’s a component that does that for you.

      Look for SDWebImage on Xamarin Component Store and add it to your project:

      image

      Doing that adds to ImageView control a SetImage extension method that accepts a Uri and does all the work for you, usage is very easy, just write something like:

      NSUrl url=new NSUrl("http://thechromenews.com/wp-content/uploads/2015/11/Apple-Logo-4.png"); MyImage.SetImage(url,null,null);

      If you try this code you’ll discover that it doesn’t work, why? is the component buggy? well no, if you try it on older iOS versions it works fine.

      Also this quite common alternative raises an exception on iOS 9.x

      private UIImage FromUri(string uri) { using (var url = new NSUrl(uri)) using (var data = NSData.FromUrl(url)) return UIImage.LoadFromData(data); }

      Ok, so what is the problem? well Apple decided that starting from iOS 9.0 all communications must use ATS (app transport security) and if you want to change this behavior you have to add an entry into info.plist file.

      This blog post describes ATS in detail and I encourage you to read it: http://ste.vn/2015/06/10/configuring-app-transport-security-ios-9-osx-10-11/

      To cut a long story short: Add this entry to your info.plist

      <key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key> <true/> </dict>

      And everything will work as expected. Smile

      HTH