
Recently it became known about the purchase of Xamarin by Microsoft. This news has not gone unnoticed among the developer community, as well as among corporate clients. In this regard, the stories become more relevant, where the Microsoft Full Stack environment requires the integration of mobile solutions that do not lead to the need to dramatically expand the competence set of the IT-calving, or the company as a whole. For such scenarios, the choice of Xamarin as a component that fits well with a puzzle consisting of SharePoint, ASP.NET MVC, WebAPI services and Azure becomes concise.
This article describes the method of mobile application distribution within the company, mainly at the prototyping stage, using the listed Microsoft technology stack.
The method described in the article, despite the bias in the .NET environment, is applicable to iOS applications written using any other development tool, be it Apache Cordova or a classic native.
Introduction
')
In my previous
article, I looked at how to distribute corporate iOS applications through an MDM solution using the example of OS X Server. This article will focus on the method of distributing applications by reference, using the Microsoft technology stack in the arsenal.
Why does the article focus on Microsoft tools? The answer lies on the surface. If the company is large, then most likely we are dealing with SharePoint, and therefore employees who have experience in developing .NET. However, all the same can be done on other technologies, for example, PHP.
As a rule, the method of distributing by reference will be chosen in cases when the number of users is very limited and they do not need automatic updating of the application, or, for the period of developing a prototype, when there is a group of testers or project curators within the company.
NoteMicrosoft also has an MDM solution based on System Center Configuration Manager and Windows Intune. You can get more information about them by clicking on the links
one ,
two and
three .
Formulation of the problem
Let's define the tasks that we set for ourselves and the resources that we have to accomplish them:
- The application should be distributed simply as an installable file;
- The solution should be implemented without the use of third-party specialized services;
- To create an application using the standard developer account Apple Developer Program;
We list the disadvantages that need to be considered before using our chosen method:
- E-mail will most likely be used to notify users of the new version of the application;
- We do not have a tool to automatically update applications, in case a critical error is detected, or, the problem is in security;
- You are limited, roughly, to 100 users;
- Each time you add a new user, you have to manually perform a series of actions and rebuild the application;
A brief sequence of actions when adding new users (iOS devices) is as follows:
- Get the UDID of the device to add;
- Add a device UDID to the developer console on the Apple site ;
- Add a device to the distribution profile (Provisioning Profile) of the desired application;
- Rebuild the application with the modified Provisioning Profile;
- Post a new version of the application on a web resource;
Getting the UDID of a device is possible using iTunes or Apple Configurator 2. However, the natural desire is to automate this process. This is possible using profiles (
iOS Configuration Profile ), which are files with the extension * .mobileconfig, and having an XML structure.
In short, it works like this: in the * .mobileconfig file, you specify the parameters you want to request from the iOS device (in our case, the UDID), and the return URL where the iOS device will send the response XML file with the filled fields.
Ensuring the ability to download and install the application for a direct link also has a number of features that we consider in this article. One of them is the need to use HTTPS.
Conceptual design and work planning
So that you can estimate the scope of actions when using this method, I have prepared two schemes.
Spreading an app by reference using an Apple Developer Program account Distributing the application by reference using the Apple Developer Enterprise Program account As you can see, using the standard Apple Developer Program account incurs a lot of overhead. Nevertheless, we consider this option as the most difficult.
I divided my narrative into three sections, so that it was convenient to perceive the information in the desired sequence. We will call them "steps." So let's take a quick look at what we have to do.
Step 1: Get the UDID of the user's iOS device:
- Create a profile * .mobileconfig, indicating the required fields;
- Posting on the web service profile * .mobileconfig, available for download;
- User: downloads a profile posted on an html page via Safari on iPhone;
- User: sets the profile, then sees the html-page “Thank you!”;
- The UDID of the user is saved on the server, after which the administrator manually adds this UDID in the account of the iOS developer;
Step 2: Install the application via the link:
- Export * .ipa-pack of the application in XCode and prepare images;
- When exporting a package, specify the path to it on the server;
- Put on server: manifest.plist, myApp.ipa, image.57x57.png, image.512x512.jpg - for example, in the same folder app-files;
- Allow downloading files on server: .jpg .png .plist .ipa;
- On the html-page to give a special link to manifest.plist, format itms-services: //? Action = download-manifest;
- The web resource must be accessible via https with a valid SSL certificate;
- The user follows the special link and installs the application;
Step 3: Deployment in a corporate environment based on Windows Server 2012 (contains changes to Step 2, if external sites with valid SSL certificates are not available to you):
- Install and configure the DNS server;
- Install and configure IIS;
- Creating and installing SSL certificates;
- Setup and build sites for distribution;
NoteI deliberately provide a detailed description of all stages and intermediate actions so that people, even with superficial knowledge in this area, have no difficulty in setting up the solution described. Therefore, please be lenient. The article is marked as "educational material". Thank.
Step 1: Get the UDID of the user's iOS device
To obtain the UDID of an iOS device, we will use ASP.NET WebAPI 2. This is a convenient solution that will immediately provide us with:
- Dialogue with the user through MVC controllers;
- Receiving and processing an XML file from an iOS device via an API controller;
- Storage of profile files and database of registered UDIDs;
Creating a WebAPI project As a platform in
Step 1 and 2 I will use Microsoft Azure. By default, a valid SSL certificate is provided for * .azurewebsites.net sites, which we will need in
Step 2. Of course, for corporate use, you also need to provide, at a minimum, the simplest authorization. However, this is much beyond the scope of this article.
Create a * .mobileconfig file and put it in the directory of the WebAPI project “Downloads / corp-apps.mobileconfig”
Content of * .mobileconfig file<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>PayloadContent</key> <dict> <key>URL</key> <string>http://iphone-udid.azurewebsites.net/api/xml</string> <key>DeviceAttributes</key> <array> <string>UDID</string> <string>IMEI</string> <string>ICCID</string> <string>VERSION</string> <string>PRODUCT</string> </array> </dict> <key>PayloadOrganization</key> <string>Corp Apps</string> <key>PayloadDisplayName</key> <string>CorpApps</string> <key>PayloadVersion</key> <integer>1</integer> <key>PayloadUUID</key> <string>B43A078F-E0E2-4F52-B1E6-C03AD7032EDF</string> <key>PayloadIdentifier</key> <string>com.CorpApps.profile-service</string> <key>PayloadDescription</key> <string>This temporary profile will be used to find and display your current device's UDID.</string> <key>PayloadType</key> <string>Profile Service</string> </dict> </plist>
In this file, two fields are noteworthy:
The URL is the address of our API controller that will process the XML file sent from the iOS device;
In my case, I’ll provide a link to a site hosted in Azure, where / api / xml is the POST method of the WebAPI controller:
http://iphone-udid.azurewebsites.net/api/xml
PayloadUUID - the easiest way to describe this field is as a unique GUID, which should not be repeated within the same iOS device.
A unique UUID (PayloadUUID) can be generated on OS X using the “uuidgen” utility:
Using the uuidgen utility os-x-server:~ zanael$ uuidgen -- generate a universally unique identifier usage: uuidgen [-hdr] -hdr emit result in form suitable for coping into a header os-x-server:~ zanael$ uuidgen B43A078F-E0E2-4F52-B1E6-C03AD7032EDF os-x-server:~ zanael$
Result of running the uuidgen utility Create an XML file in which we will store the registered UDIDs. Let's call it udids.xml, and put it in the directory of the WebAPI project “App_Data / udids.xml”.
XML file structure for storing registered UDIDs <?xml version="1.0" encoding="utf-8"?> <udids> <iPhone> <TimeAdded></TimeAdded> <UDID></UDID> </iPhone> </udids>
Add a permission to Web.config for downloading profile files.
Necessary changes in Web.config <?xml version="1.0" encoding="utf-8"?> <configuration> <system.webServer> <staticContent> <mimeMap fileExtension=".mobileconfig" mimeType="application/x-apple-aspen-config" /> </staticContent> </system.webServer> </configuration>
Add a model to store information about registered UDID in the Models folder.
IPhoneUDID.cs file namespace iPhoneUDID.Models { public class iPhoneUDID { public string TimeAdded { get; set; } public string UDID { get; set; } } }
Create a HomeController (MVC controller) in the Controllers folder and add a method to it to display the list of registered UDIDs from XML.
HomeController.cs file using System; using System.Collections.Generic; using System.Web.Mvc; using System.Xml.Linq; namespace iPhoneUDID.Controllers { public class HomeController : Controller { [HttpGet] public ActionResult Index() { ViewBag.Title = "Home Page"; XDocument databaseXML; try { databaseXML = XDocument.Load(System.Web.Hosting.HostingEnvironment.MapPath("~/App_Data/udids.xml")); } catch (Exception exp) { databaseXML = new XDocument(new XElement("udids")); } List<Models.iPhoneUDID> UDIDs = new List<Models.iPhoneUDID>(); XElement iPhones = databaseXML.Element("udids"); foreach (XElement e in iPhones.Elements("iPhone")) { UDIDs.Add(new Models.iPhoneUDID { TimeAdded = e.Element("TimeAdded").Value, UDID = e.Element("UDID").Value }); } ViewBag.UDIDs = UDIDs; return View(); } } }
Add a View (Index.cshtml) for the HomeController, which will greet the user and ask them to register their UDID.
When you click on the
Take UDID button, the user will download the profile, the iOS device will understand what parameters we need and send them to the URL that we specified in the * .mobileconfig file in the XML format.
File /Views/Home/Index.cshtml <div class="jumbotron"> <h1>Get your UDID</h1> <p class="lead">Please, reach this page in Mobile Safari from your iPhone.</p> <p><a href="/downloads/corp-apps.mobileconfig" class="btn btn-primary btn-lg">Take UDID</a></p> </div> <div class="row"> <p> @{ foreach (iPhoneUDID.Models.iPhoneUDID item in ViewBag.UDIDs) { <h5>TimeAdded: @item.TimeAdded, UDID: @item.UDID</h5> } } </p> </div> <div class="row"> @Html.ActionLink("Clear UDIDs list", "ClearHistory", "Home", null, new { @class = "btn btn-primary btn-large" }) </div>
Create an XmlController (WebApi2 controller) in the Controllers folder, which will catch the XML file from the iOS device, and save the UDID obtained from it to the local XML.
Since we are using a Windows machine, the second part of the file will be in a different encoding. This can be fixed using the * .plist conversion library. They can be found on GitHub, but since we only need the UDID, we can take it elementary from a given position in a row. This will allow us not to pull extra dependencies.
XmlController.cs file using System; using System.Net; using System.Net.Http; using System.Web.Http; using System.Xml.Linq; namespace iPhoneUDID.Controllers { public class XmlController : ApiController { [HttpPost] public HttpResponseMessage PostRawXMLMessage(HttpRequestMessage request) { string plist = request.Content.ReadAsStringAsync().Result; int begin = plist.IndexOf("UDID") + 20; int end = plist.IndexOf("<", begin); string UDID = plist.Substring(begin, end - begin); XDocument databaseXML; try { databaseXML = XDocument.Load(System.Web.Hosting.HostingEnvironment.MapPath("~/App_Data/udids.xml")); } catch (Exception exp) { databaseXML = new XDocument(new XElement("udids")); } databaseXML.Element("udids").Add( new XElement("iPhone", new XElement("TimeAdded", DateTime.Now.ToLongTimeString() + " - " + DateTime.Now.ToShortDateString()), new XElement("UDID", UDID))); databaseXML.Save(System.Web.Hosting.HostingEnvironment.MapPath("~/App_Data/udids.xml")); HttpResponseMessage response = request.CreateResponse(HttpStatusCode.MovedPermanently); response.Headers.Add("Location", "/Thanks"); return response; } } }
Create an ThanksController (MVC controller) to which the user will be redirected after receiving his UDID.
ThanksController.cs file using System.Web.Mvc; namespace iPhoneUDID.Controllers { public class ThanksController : Controller { [HttpGet] public ActionResult Index() { ViewBag.Title = "Thanks Page"; return View(); } } }
Add a View (Index.cshtml) for ThanksController.
File /Views/Thanks/Index.cshtml <div class="jumbotron"> <h1>Thanks for Attending!</h1> </div>
To clear the local XML with the received UDID, add the ClearHistory method to the HomeController (MVC controller).
HomeController.cs file [HttpGet] public ActionResult ClearHistory() { ViewBag.Title = "Home Page"; XDocument databaseXML = new XDocument(new XElement("udids")); databaseXML.Save(Server.MapPath("/App_Data/udids.xml")); ViewBag.UDIDs = new List<Models.iPhoneUDID>(); return View("Index"); }
This is how the general Layout (_Layout.cshtml) looks like - standard for the template
_Layout.cshtml file <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width" /> <title>@ViewBag.Title</title> @Styles.Render("~/Content/css") @Scripts.Render("~/bundles/modernizr") </head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <body> <div class="navbar navbar-inverse navbar-fixed-top"> <div class="container"> <div class="navbar-header"> <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse"> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> @Html.ActionLink(" ", "Index", "Home", new { area = "" }, new { @class = "navbar-brand" }) </div> <div class="navbar-collapse collapse"> <ul class="nav navbar-nav"> <li>@Html.ActionLink(" ", "Index", "Home", new { area = "" }, null)</li> <li>@Html.ActionLink("API", "Index", "Help", new { area = "" }, null)</li> </ul> </div> </div> </div> <div class="container body-content"> @RenderBody() <hr /> <footer> <p>© @DateTime.Now.Year – ASP.NET</p> </footer> </div> @Scripts.Render("~/bundles/jquery") @Scripts.Render("~/bundles/bootstrap") @RenderSection("scripts", required: false) </body> </html>
Now, all the user needs is to go to the site and click a couple of buttons.
User action

If you click More Details 


After this, we will see its UDID on the site.
Finally, we have in our hands the UDID of the iOS device, which we need to register with our developer account.
Let's go to
the Apple
website for developers in the Member Center section.
Add the UDID of the iOS device.
If you have not yet created an App ID, do it.
Create a Provisioning Profile for your application.
Step 2: Install the application through the link
After we received the UDID of the iOS device, added it to the developer account and made changes to the Provisioning Profile, we need to provide the user with a web resource that will contain the files necessary to install the application. As such a resource, I will use Microsoft Azure, which by default provides a valid SSL certificate for * .azurewebsites.net sites. As the site name, I will choose:
https://corp-apps.azurewebsites.net
NoteInstalling an application by reference will only work if you use HTTPS with a valid SSL certificate.
As a project to create a website, you can choose the simplest template, without any controllers. All we need is an HTML page and the ability to download several additional files.
Now we can start preparing the necessary files. To do this, export the application package via Xcode.
Fill in the information needed to distribute the application. Pay attention to the file extensions.
- Title:
myApp
- App URL:
https://corp-apps.azurewebsites.net/app-files/myApp.ipa
- Display Image URL:
https://corp-apps.azurewebsites.net/app-files/image.57x57.png
- Full Size Image URL:
https://corp-apps.azurewebsites.net/app-files/image.512x512.jpg
After the export is completed in the target folder, you will see the manifest manifest.plist, in which the paths to the required resources are specified, as well as pictures of the required format and size.
The contents of the file manifest.plist <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>items</key> <array> <dict> <key>assets</key> <array> <dict> <key>kind</key> <string>software-package</string> <key>url</key> <string>https://corp-apps.azurewebsites.net/app-files/myApp.ipa</string> </dict> <dict> <key>kind</key> <string>display-image</string> <key>url</key> <string>https://corp-apps.azurewebsites.net/app-files/image.57x57.png</string> </dict> <dict> <key>kind</key> <string>full-size-image</string> <key>url</key> <string>https://corp-apps.azurewebsites.net/app-files/image.512x512.jpg</string> </dict> </array> <key>metadata</key> <dict> <key>bundle-identifier</key> <string>com.habr.hellohabr001</string> <key>bundle-version</key> <string>0.0.1</string> <key>kind</key> <string>software</string> <key>title</key> <string>myApp</string> </dict> </dict> </array> </dict> </plist>
Now, we need to allow downloading of the specified file types from the server. This can be done by making changes to the Web.config file.
Necessary changes in the Web.config file <?xml version="1.0" encoding="utf-8"?> <configuration> <system.webServer> <staticContent> <mimeMap fileExtension=".jpg" mimeType="image/jpg" /> <mimeMap fileExtension=".png" mimeType="image/png" /> <mimeMap fileExtension=".plist" mimeType="text/plain" /> <mimeMap fileExtension=".ipa" mimeType="application/octet-stream" /> </staticContent> </system.webServer> </configuration>
And finally, we will add for users an html-page with a special link to download the application.
Index.html file <!doctype html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title> </title> <link rel="stylesheet" href="dist/bootstrap.min.css"> </head> <body> <div class="container"> <br><br> <h1 class="text-center">Hello Apache Cordova</h1> <p class="text-center"> <a href="itms-services://?action=download-manifest&url=https://corp-apps.azurewebsites.net/app-files/manifest.plist" class="btn btn-info" type="button">Install App</a> </p> <br><br> </div> </body> </html>
Great, all the user needs to do is press a few buttons.
To emphasize the universality of the method in relation to the development tools, the example used an application written in Apache Cordova. The same is true for other tools, such as Xamarin.
Step 3: Deploy in a Windows Server 2012-based Enterprise Environment
So, we come to the most difficult scenario when external sites are not available to you. In this case, we will use Windows Server 2012 and IIS 8.
For clarity, we will deploy two separate sites:
NoteInstalling HTTPS for the iphone-udid-zzzz.com site is optional, just take this case to demonstrate the configuration of IIS.
To access sites by specified domain names, a configured DNS server is needed (in the example, an Active Directory domain controller, DNS server, and the sites themselves are deployed on the same machine).
Let's start creating direct viewing zones for our sites. To do this, use the server manager.
Let's create a forward view zone for the UDID site of the iOS device:
iphone-udid-zzzz.com .
For academic purposes, I will provide network settings that are important to consider.
Read moreServer network adapter settings (where 192.168.0.1 is the IP address of the WiFi router)

DNS settings for the WiFi router. In the case of D-Link, the order of DNS servers is important.

Network Adapter Settings for a Windows Server 2012 Virtual Machine

Create a node (A or AAAA).
Read more
Let's write down the IP address of our server

Make sure that the site is accessible through the FQDN name. Perform a DNS cache flush.


Great, we see that everything works.
We repeat the same chain of actions for the application download site:
corp-apps-zzzz.com .
Now we can proceed to the installation and configuration of IIS.
Create a stub for our sites.
Since, to install applications on iOS devices by reference, HTTPS support is required - let's start creating SSL certificates. Unfortunately, the SSL certificates generated by IIS do not suit us, so we will use the OpenSSL utility.
This guide uses the Win32 OpenSSL command line utility, which can be downloaded from the
link .
OpenSSL installation detailsSelect the bitness of your operating system.
Win64 OpenSSL v1.0.2e (16MB Installer) was selected for this Windows Server 2012

Moments to which attention should be paid during installation.


After installing OpenSSL, create an
OpenSSL-Certificates folder on drive
C.Run the command prompt. Create a certificate for
iphone-udid-zzzz.com .
Using the openssl utility to create a certificate C:\Users\devin> cd c:\OpenSSL-Certificates c:\OpenSSL-Certificates> set RANDFILE=c:\OpenSSL-Certificates\.rnd c:\OpenSSL-Certificates> set OPENSSL_CONF=C:\OpenSSL-Win64\bin\openssl.cfg c:\OpenSSL-Certificates> c:\OpenSSL-Win64\bin\openssl.exe OpenSSL> genrsa -out iphone-udid-zzzz.key 2048 OpenSSL> req -new -x509 -sha256 -key iphone-udid-zzzz.key -out iphone-udid-zzzz.cer -days 365 -subj /CN=iphone-udid-zzz.com OpenSSL> pkcs12 -export -out iphone-udid-zzzz.pfx -inkey iphone-udid-zzzz.key -in iphone-udid-zzzz.cer Enter Export Password: Verifying - Enter Export Password: OpenSSL> exit c:\OpenSSL-Certificates>
Similarly, create a certificate for
corp-apps-zzzz.com :
Using the openssl utility to create a certificate C:\Users\devin> cd c:\OpenSSL-Certificates c:\OpenSSL-Certificates> set RANDFILE=c:\OpenSSL-Certificates\.rnd c:\OpenSSL-Certificates> set OPENSSL_CONF=C:\OpenSSL-Win64\bin\openssl.cfg c:\OpenSSL-Certificates> c:\OpenSSL-Win64\bin\openssl.exe OpenSSL> genrsa -out corp-apps-zzzz.key 2048 OpenSSL> req -new -x509 -sha256 -key corp-apps-zzzz.key -out corp-apps-zzzz.cer -days 365 -subj /CN=corp-apps-zzzz.com OpenSSL> pkcs12 -export -out corp-apps-zzzz.pfx -inkey corp-apps-zzzz.key -in corp-apps-zzzz.cer Enter Export Password: Verifying - Enter Export Password: OpenSSL> exit c:\OpenSSL-Certificates>
The next step is importing the newly created * .pfx certificates into IIS.
Now we can
change the bindings to provide an HTTPS connection.
For site: iphone-udid-zzzz.com For a site: corp-apps-zzzz.com Great, the next step is to make changes to the WebAPI project for the
iphone-udid-zzzz.com site.
The
Web.config file, to eliminate problems with WebDAV and 405 errors, the
system.webServer section.
Necessary changes in the Web.config file <system.webServer> <validation validateIntegratedModeConfiguration="false" /> <modules runAllManagedModulesForAllRequests="true"> <remove name="WebDAVModule"/> </modules> <handlers> <remove name="ExtensionlessUrlHandler-Integrated-4.0" /> <add name="ExtensionlessUrl-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" /> <remove name="OPTIONSVerbHandler" /> <remove name="TRACEVerbHandler" /> <remove name="WebDAV" /> </handlers> <staticContent> <mimeMap fileExtension=".mobileconfig" mimeType="application/x-apple-aspen-config" /> </staticContent> </system.webServer>
Certificates will also need to add changes to
Web.config .
Read more <system.webServer> <staticContent> <remove fileExtension=".mobileconfig" /> <mimeMap fileExtension=".mobileconfig" mimeType="application/x-apple-aspen-config" /> <remove fileExtension=".crt" /> <mimeMap fileExtension=".crt" mimeType="application/x-x509-ca-cert" /> </staticContent> </system.webServer>
File
/Downloads/iphone-udid-zzzz.mobileconfig - changed URL.
Read more <key>URL</key> <string>https://iphone-udid-zzzz.com:9001/api/xml</string>
The generated
iphone-udid-zzzz.cer certificate has been added to the
/ Downloads / folder , for which you need to change the extension to
* .crt . Otherwise, on the iOS device, it will open in the browser simply as a text file.
File
/Views/Home/Index.cshtml - URLs (href) have been changed, a link to download an SSL certificate has been added.
Necessary changes in the Index.cshtml file <div class="jumbotron"> <h1>Get your UDID</h1> <p><a href="/downloads/iphone-udid-zzzz.mobileconfig" class="btn btn-primary btn-lg">Take UDID</a></p> </div> <div class="row"> <a href="/downloads/iphone-udid-zzzz.crt" download class="btn btn-info">Install SSL-Certificate</a> <p> @{ foreach (iPhoneUDID.Models.iPhoneUDID item in ViewBag.UDIDs) { <h5>TimeAdded: @item.TimeAdded, UDID: @item.UDID</h5> } } </p> </div> <div class="row"> @Html.ActionLink("Clear UDIDs list", "ClearHistory", "Home", null, new { @class = "btn btn-primary btn-large" }) </div>
File
/Controllers/XmlController.cs - added try / catch construction - wrapper for plist parsing (UDID).
Read more using System; using System.Net; using System.Net.Http; using System.Web.Http; using System.Xml.Linq; namespace iPhoneUDID.Controllers { public class XmlController : ApiController { [HttpPost] public HttpResponseMessage PostRawXMLMessage(HttpRequestMessage request) { string plist = request.Content.ReadAsStringAsync().Result; string UDID = "Error"; try { int begin = plist.IndexOf("UDID") + 20; int end = plist.IndexOf("<", begin); UDID = plist.Substring(begin, end - begin); } catch (Exception exc) {
We can start building a project for the
iphone-udid-zzzz.com site.
We copy the received files in the corresponding folder on the server.
Also, you must allow changes to the
udids.xml file within the directory on the server.
From this point on, users can register the UDID of their iOS devices on the site:
https://iphone-udid-zzzz.com:9001
In order to test the POST registration request UDID, I recommend using the free extension for Google Chrome -
Postman .
Let's start building the project for the
corp-apps-zzzz.com website.
Web.config file.
Content of the Web.config file <?xml version="1.0" encoding="utf-8"?> <configuration> <system.webServer> <staticContent> <remove fileExtension=".jpg" /> <mimeMap fileExtension=".jpg" mimeType="image/jpg" /> <remove fileExtension=".png" /> <mimeMap fileExtension=".png" mimeType="image/png" /> <remove fileExtension=".plist" /> <mimeMap fileExtension=".plist" mimeType="text/plain" /> <remove fileExtension=".ipa" /> <mimeMap fileExtension=".ipa" mimeType="application/octet-stream" /> <remove fileExtension=".crt" /> <mimeMap fileExtension=".crt" mimeType="application/x-x509-ca-cert" /> </staticContent> </system.webServer> </configuration>
File
index.html - changed URL (href), added link to download SSL certificate.
The user must install this certificate before installing the application. Otherwise, it will receive a certificate authentication error.
Necessary changes in the index.html file <!doctype html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title> iOS </title> <link rel="stylesheet" href="dist/bootstrap.min.css"> <script src="dist/jquery-1.11.3.min.js"></script> <style> h4 {line-height: 25px;} </style> </head> <body> <div class="container"> <br><br> <h1 class="text-center">Hello Apache Cordova</h1> <p class="text-center"> <a href="itms-services://?action=download-manifest&url=https://corp-apps-zzzz.com:9002/app-files/manifest.plist" class="btn btn-info" type="button">Install App</a> <a href="/app-files/corp-apps-zzzz.crt" download class="btn btn-info">Install SSL-Certificate</a> </p> <br><br> </div> </body> </html>
File
manifest.plist - changed URL (added ports).
Necessary changes in the manifest.plist file <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>items</key> <array> <dict> <key>assets</key> <array> <dict> <key>kind</key> <string>software-package</string> <key>url</key> <string>https://corp-apps-zzzz.com:9002/app-files/myApp.ipa</string> </dict> <dict> <key>kind</key> <string>display-image</string> <key>url</key> <string>https://corp-apps-zzzz.com:9002/app-files/image.57x57.png</string> </dict> <dict> <key>kind</key> <string>full-size-image</string> <key>url</key> <string>https://corp-apps-zzzz.com:9002/app-files/image.512x512.jpg</string> </dict> </array> <key>metadata</key> <dict> <key>bundle-identifier</key> <string>com.habr.hellohabr001</string> <key>bundle-version</key> <string>0.0.1</string> <key>kind</key> <string>software</string> <key>title</key> <string>myApp</string> </dict> </dict> </array> </dict> </plist>
The generated certificate
corp-apps-zzzz.cer has been added to the
/ app-files / folder , for which you need to change the extension to
* .crt . Otherwise, on the iOS device, it will open in the browser simply as a text file.
Now, to install the application, the user needs to press just a few buttons by going to the website:
https://corp-apps-zzzz.com:9002
Conclusion
In this article, we looked at how to distribute iOS applications by reference using the Microsoft technology stack.
In order to review, I posted a demo projects on GitHub.
- The sources of projects using external sites for placement can be found here ;
- The sources of projects that use windows server as a platform within the company can be found here .
I hope the article will seem useful to people starting to understand this topic.