{"id":762,"date":"2014-11-09T21:43:11","date_gmt":"2014-11-10T03:43:11","guid":{"rendered":"http:\/\/dev.iachieved.it\/iachievedit\/?p=762"},"modified":"2020-07-14T21:47:35","modified_gmt":"2020-07-15T02:47:35","slug":"using-property-lists-for-api-keys-in-swift-applications","status":"publish","type":"post","link":"https:\/\/dev.iachieved.it\/iachievedit\/using-property-lists-for-api-keys-in-swift-applications\/","title":{"rendered":"Using Property Lists for API Keys in Swift Applications"},"content":{"rendered":"<p><img decoding=\"async\" src=\"https:\/\/img.shields.io\/badge\/Xcode-7.3-blue.svg?style=flat\" alt=\"Xcode 7.3\" \/> <img decoding=\"async\" src=\"https:\/\/img.shields.io\/badge\/Swift-2.2-orange.svg?style=flat\" alt=\"Swift 2.2\" \/><\/p>\n<p>You&#8217;ve written an open source application for demonstration or illustrative purposes, and your application requires REST API keys for services such as Facebook, Twitter, Wunderground, or Parse or&#8230;  You get the idea.  How do you submit your application to Github for others to use without exposing your own API keys?  I can&#8217;t take credit for the original idea, but here&#8217;s a Swift take on technique described by <a href=\"http:\/\/blog.lazerwalker.com\/blog\/2014\/05\/14\/handling-private-api-keys-in-open-source-ios-apps\">Mike Lazer-Walker<\/a>.<\/p>\n<p>We&#8217;ll be using iOS <i>property list<\/i> files and a Swift wrapper.  The highlights here are that we are <i>not<\/i> checking our property list into source control (Git), but our project will reference a file called <code>ApiKeys.plist<\/code>.  If you download the project from <a href=\"https:\/\/bitbucket.org\/joeiachievedit\/apikeys.git\">Bitbucket<\/a> and try to run you&#8217;ll get an error because the file <code>ApiKeys.plist<\/code> is missing.  This is where you create your own <code>ApiKeys.plist<\/code> and put in your own API keys.<\/p>\n<p><b>Note:<\/b>  This technique we are using here is specific to <code>git<\/code>.  If you are using a different <a href=\"http:\/\/en.wikipedia.org\/wiki\/Revision_control\">revision control system<\/a> look up the feature for how to ignore certain files in your source tree (for example, in Subversion you would use the <code>svn:ignore<\/code> property).<\/p>\n<p>The general technique is to add a <code>.gitignore<\/code> file to the root directory of our project and add the following line:<\/p>\n<pre class=\"crayon:false\">\nApiKeys.plist\n<\/pre>\n<p>and then, to create a <code>ApiKeys.plist<\/code> local to your machine with something similar to the following content:<\/p>\n<p>[code]<br \/>\n&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;<br \/>\n&lt;!DOCTYPE plist PUBLIC &quot;-\/\/Apple\/\/DTD PLIST 1.0\/\/EN&quot; &quot;http:\/\/www.apple.com\/DTDs\/PropertyList-1.0.dtd&quot;&gt;<br \/>\n&lt;plist version=&quot;1.0&quot;&gt;<br \/>\n&lt;dict&gt;<br \/>\n\t&lt;key&gt;API_CLIENT_ID&lt;\/key&gt;<br \/>\n\t&lt;string&gt;MyAPIClientID&lt;\/string&gt;<br \/>\n        &lt;key&gt;API_SECRET&lt;\/key&gt;<br \/>\n        &lt;string&gt;MyAPISecret&lt;\/string&gt;<br \/>\n&lt;\/dict&gt;<br \/>\n&lt;\/plist&gt;<br \/>\n[\/code]<\/p>\n<p>Once we have that we need a clean mechanism for obtaining the values for our keys.  This is done through a utility file in Swift (we call it <code>ApiKeys.swift<\/code> for simplicity) with the contents:<\/p>\n<pre>\nimport Foundation\n\nfunc valueForAPIKey(named keyname:String) -> String {\n  \/\/ Credit to the original source for this technique at\n  \/\/ http:\/\/blog.lazerwalker.com\/blog\/2014\/05\/14\/handling-private-api-keys-in-open-source-ios-apps\n  let filePath = NSBundle.main().path(forResource: \"ApiKeys\", ofType: \"plist\")\n  let plist = NSDictionary(contentsOfFile:filePath!)\n  let value = plist?.object(forKey: keyname) as! String\n  return value\n}\n<\/pre>\n<p>The code is straightforward and meant to be called like this:<\/p>\n<pre>\nlet clientID = valueForAPIKey(keyname:\"API_CLIENT_ID\")\n<\/pre>\n<p>The routine looks for the <code>ApiKeys.plist<\/code> file in the application&#8217;s resource bundle, loads it as an <code>NSDictionary<\/code> and then looks up the value for the given key as a <code>String<\/code>.<\/p>\n<p>It should be pointed out that what this code <i>does not do<\/i> is in any way obfuscate the contents of the <code>plist<\/code>.  That is, your iOS binary will have the keys included in the resource bundle and <i>could<\/i> be extracted by someone intent on getting at them.<\/p>\n<p>Now, let&#8217;s look at the specifics on how to use this technique in your Swift projects.<\/p>\n<p><b>Step 1.<\/b>  Add <code>ApiKeys.plist<\/code> to your <code>.gitignore<\/code> file<\/p>\n<p>This is important; failure to do so will cause Xcode to try to automatically add your <code>plist<\/code> file to revision control.  We don&#8217;t want that.<\/p>\n<p><b>Step 2.<\/b>  Create <code>ApiKeys.plist<\/code><\/p>\n<p>You can either create <code>ApiKeys.plist<\/code> by hand or use Xcode to create it.  Just make sure that you&#8217;ve added <code>ApiKeys.plist<\/code> to your <code>.gitignore<\/code> file!<\/p>\n<p>To create <code>ApiKeys.plist<\/code> use <b>File &#8211; New &#8211; File<\/b> in Xcode and create a <b>Resource<\/b> file of type <b>Property List<\/b>.  Select <b>Next<\/b> and name the file <code>ApiKeys<\/code> (the <code>plist<\/code> file type will be created automatically).  <i>If you name it something other than what you put in your <code>.gitignore<\/code>, it will get added to revision control, which is not what you want.<\/i>.<\/p>\n<p><a href=\"https:\/\/dev.iachieved.it\/iachievedit\/wp-content\/uploads\/2014\/11\/createPropertyList.png\"><img loading=\"lazy\" decoding=\"async\" width=\"734\" height=\"433\" src=\"https:\/\/dev.iachieved.it\/iachievedit\/wp-content\/uploads\/2014\/11\/createPropertyList.png\" alt=\"createPropertyList\"  class=\"alignnone size-medium wp-image-781\" \/><\/a><\/p>\n<p>Also ensure that the file is included in your application target.<\/p>\n<p><a href=\"https:\/\/dev.iachieved.it\/iachievedit\/wp-content\/uploads\/2014\/11\/addApiKeysFile.png\"><img loading=\"lazy\" decoding=\"async\" width=\"461\" height=\"580\" src=\"https:\/\/dev.iachieved.it\/iachievedit\/wp-content\/uploads\/2014\/11\/addApiKeysFile.png\" alt=\"addApiKeysFile\" class=\"alignnone size-medium wp-image-780\" \/><\/a><\/p>\n<p>Now add the API keys you need for your application to your <code>ApiKeys.plist<\/code> file.  Select the <code>ApiKeys.plist<\/code> file in Xcode and click on the <code>Root<\/code> dictionary line, then right-click and choose <b>Add Row<\/b>.  Double-click on the text that says <b>New item<\/b> and rename it to <code>API_CLIENT_ID<\/code>.  Double-click on the <b>Value<\/b> column and type in your actual string.  For our purposes I&#8217;ve just put <code>MyAPIClientID<\/code>.<\/p>\n<p><a href=\"https:\/\/dev.iachieved.it\/iachievedit\/wp-content\/uploads\/2014\/11\/SetAPICLIENTID.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/dev.iachieved.it\/iachievedit\/wp-content\/uploads\/2014\/11\/SetAPICLIENTID.png\" alt=\"SetAPICLIENTID\" width=\"691\" height=\"244\" class=\"alignnone size-full wp-image-779\" \/><\/a><\/p>\n<p><b>Step 3.<\/b>  Create <code>ApiKeys.swift<\/code><\/p>\n<p>We want a simple wrapper for obtaining our keys, so create a new file called <code>ApiKeys.swift<\/code> and in it place the following:<\/p>\n<pre>\nimport Foundation\n\nfunc valueForAPIKey(named keyname:String) -> String {\n  \/\/ Credit to the original source for this technique at\n  \/\/ http:\/\/blog.lazerwalker.com\/blog\/2014\/05\/14\/handling-private-api-keys-in-open-source-ios-apps\n  let filePath = NSBundle.main().path(forResource: \"ApiKeys\", ofType: \"plist\")\n  let plist = NSDictionary(contentsOfFile:filePath!)\n  let value = plist?.object(forKey: keyname) as! String\n  return value\n}\n<\/pre>\n<p><b>Step 4.<\/b>  Use the <code>valueForAPIKey<\/code> Routine<\/p>\n<pre>\nlet clientID = valueForAPIKey(named:\"API_CLIENT_ID\")\n<\/pre>\n<p>And that&#8217;s it!  Once you have your <code>clientID<\/code> you can add it to whatever REST calls you need to (or if you are dealing with an annoying API add it as a special HTTP <code>X-<\/code> header).<\/p>\n<p>Now, I will confess, it is unclear why there isn&#8217;t a more elegant way to do this in Xcode.  Although this technique is serviceable it isn&#8217;t very DRY (don&#8217;t-repeat-yourself), but then again, how many times have started a new project only to repeat the same &#8220;bootstrap&#8221; steps such as adding AFNetworking, CocoaLumberjack, and all of the other popular frameworks?  What would be handy is the ability for Xcode to obtain API keys and other confidential information from an application like Keychain and compile them in a secure manner.  <i>Que ser\u00e1, ser\u00e1<\/i> I suppose.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>You&#8217;ve written an open source application for demonstration or illustrative purposes, and your application requires REST API keys for services such as Facebook, Twitter, Wunderground, or Parse or&#8230; You get the idea. How do you submit your application to Github for others to use without exposing your own API keys? I can&#8217;t take credit for [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":3108,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5,2],"tags":[],"class_list":["post-762","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-swift","category-xcodetips"],"_links":{"self":[{"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/posts\/762"}],"collection":[{"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/comments?post=762"}],"version-history":[{"count":34,"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/posts\/762\/revisions"}],"predecessor-version":[{"id":2691,"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/posts\/762\/revisions\/2691"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/media\/3108"}],"wp:attachment":[{"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/media?parent=762"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/categories?post=762"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/tags?post=762"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}