<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.3.3">Jekyll</generator><link href="https://blach.io/atom.xml" rel="self" type="application/atom+xml" /><link href="https://blach.io/" rel="alternate" type="text/html" /><updated>2024-04-06T17:25:33+02:00</updated><id>https://blach.io/atom.xml</id><title type="html">blach.io</title><subtitle>Things I&apos;ve stumbled across while developing apps for iPad, iPhone and Mac.</subtitle><author><name>Alexander Blach</name><email>alexander@blach.io</email></author><entry><title type="html">Removal of Textastic’s Google Drive client</title><link href="https://blach.io/2024/03/28/removal-of-textastic-google-drive-client/" rel="alternate" type="text/html" title="Removal of Textastic’s Google Drive client" /><published>2024-03-28T19:20:00+01:00</published><updated>2024-03-28T19:20:00+01:00</updated><id>https://blach.io/2024/03/28/removal-of-textastic-google-drive-client</id><content type="html" xml:base="https://blach.io/2024/03/28/removal-of-textastic-google-drive-client/"><![CDATA[<p>Google’s changes to the Google Drive API are forcing me to remove the built-in Google Drive client from Textastic for iOS/iPadOS.</p>

<h2 class="no_toc" id="contents">Contents</h2>

<ul id="markdown-toc">
  <li><a href="#what-happened" id="markdown-toc-what-happened">What happened?</a>    <ul>
      <li><a href="#the-alternative-suggested-by-google-wouldnt-work" id="markdown-toc-the-alternative-suggested-by-google-wouldnt-work">The alternative suggested by Google wouldn’t work</a></li>
    </ul>
  </li>
  <li><a href="#what-happens-next" id="markdown-toc-what-happens-next">What happens next?</a></li>
  <li><a href="#how-can-i-continue-to-access-files-in-google-drive" id="markdown-toc-how-can-i-continue-to-access-files-in-google-drive">How can I continue to access files in Google Drive?</a>    <ul>
      <li><a href="#limitations" id="markdown-toc-limitations">Limitations</a></li>
    </ul>
  </li>
  <li><a href="#what-are-the-alternatives-to-google-drive" id="markdown-toc-what-are-the-alternatives-to-google-drive">What are the alternatives to Google Drive?</a></li>
  <li><a href="#further-reading" id="markdown-toc-further-reading">Further Reading</a></li>
</ul>

<h2 id="what-happened">What happened?</h2>

<p>Google made some changes to the <a href="https://developers.google.com/drive/api/guides/api-specific-auth">Google Drive API scopes</a> and decided to classify some of them as “sensitive” or “restricted”.</p>

<p>Textastic includes file transfer clients for (S)FTP, Dropbox, WebDAV and Google Drive, which enable the uploading and downloading of individual files and whole folder trees, the creation of folders and the deletion of files and folders.</p>

<p>To implement file transfers for Google Drive, Textastic has been using the <code class="language-plaintext highlighter-rouge">drive</code> scope since version 6.1, which was released <strong>in 2016</strong>. This scope gives the app the ability to view and manage all files in a user’s Google Drive account.</p>

<p>The <code class="language-plaintext highlighter-rouge">drive</code> scope has been re-classified as “<strong>restricted</strong>” and Google has started to enforce this change for more apps, including Textastic.</p>

<p>In order to continue using that scope, Google requires me to complete a “CASA Tier 3 security assessment” for Textastic. This assessment is required <strong>annually</strong>.</p>

<p>“CASA Tier 3 is a comprehensive assessment that tests the application, the application deployment infrastructure and any user data storage location.”</p>

<p>According to Google, the “CASA assessment can take up to 6 weeks depending on how engaged and responsive you are in the whole process”. This assessment is conducted and validated by one of the <a href="https://appdefensealliance.dev/casa/casa-assessors">CASA authorized labs</a>.</p>

<p>The <a href="https://appdefensealliance.dev/casa/casa-tiering">CASA Tiering website</a> estimates that a tier 3 assessment takes <strong>60 lab hours</strong>.</p>

<p>I contacted DEKRA, which is one of the labs listed by Google. They told me that the estimated execution time is 10 days, <strong>costing €9500</strong>.</p>

<p>Obviously, annual costs of this magnitude just to support Google Drive in Textastic are not sustainable - especially considering that there is no additional benefit for my business.</p>

<p>In addition to that, the lab staff would need “access to the development environment (user/password) for the application, access to source code, credentials and architecture documentation, etc.”, which I’m not necessarily comfortable with.</p>

<h3 id="the-alternative-suggested-by-google-wouldnt-work">The alternative suggested by Google wouldn’t work</h3>

<p>As an alternative, Google wants developers to switch from the <code class="language-plaintext highlighter-rouge">drive</code> scope to the <code class="language-plaintext highlighter-rouge">drive.file</code> scope. However, this scope would only allow Textastic to create new files and modify files created by Textastic.</p>

<p>It would <em>not</em> allow access to other existing files in Google Drive. So after connecting to a Google Drive account, the file list displayed by Textastic would be empty and the user would not be able to download any existing files.</p>

<p>There is also the “Google Picker API”, which would allow a user to pick individual files from Google Drive to share with an app. This API however is only available as a JavaScript library for web apps, not for mobile apps.</p>

<p>While it might be possible to use the Google Picker API in a web view, it does not allow the user to give Textastic access to folders. As a result it wouldn’t be very useful anyway since the same can be accomplished with the Google Drive app’s file provider and the iOS document picker.</p>

<h2 id="what-happens-next">What happens next?</h2>

<p>For the reasons mentioned above, I have decided to remove the built-in Google Drive client from Textastic.</p>

<p>Google gave me a deadline of May 6, 2024.</p>

<p>Around that date, there’s going to be an ongoing <strong>100 user limit</strong> for Google Drive connections added to Textastic and the Google Drive login will display an <a href="https://support.google.com/cloud/answer/7454865"><strong>unverified app screen</strong></a>.</p>

<p>So even if your Google Drive connection is still working now, I don’t know exactly how long it will continue to work, but I expect it to start failing in May.</p>

<p>In Textastic’s next update, version 10.2, there will be a warning if you try to use or add a Google Drive connection, letting you know that it will eventually stop working. The warning will include a link to this post.</p>

<h2 id="how-can-i-continue-to-access-files-in-google-drive">How can I continue to access files in Google Drive?</h2>

<p>Please install the <a href="https://apps.apple.com/us/app/google-drive/id507874739">official Google Drive app</a> on your iPad or iPhone. It includes a file provider, so you can enable Google Drive as a location in the Files app.</p>

<p>You can find more information in this Apple support article: <a href="https://support.apple.com/en-us/102238">“Use third-party cloud apps in the Files app”</a>.</p>

<p>After adding Google Drive to the Files app, you can <a href="https://www.textasticapp.com/v10/manual/integration_other_apps/external_files_folders.html#opening-files">use the “<strong>Open…</strong>” command</a> in Textastic to open individual files from Google Drive using the document picker.</p>

<p>To upload a file to Google Drive, you can use the <strong>share sheet</strong>. Alternatively, tap and hold a file in a file list in Textastic and select “<strong>Export</strong>” from the menu.</p>

<h3 id="limitations">Limitations</h3>

<p>Unfortunately, the Google Drive file provider doesn’t support opening folders, so the <a href="https://www.textasticapp.com/v10/manual/integration_other_apps/external_files_folders.html#adding-external-folders">“Add External Folder…”</a> command won’t work for folders in Google Drive.</p>

<p>Also, the “Create External File…” command will result in the error “Couldn’t communicate with a helper application” (<em>com.google.DriveKit error 11</em>) when you try to create an external file in Google Drive.</p>

<p>These are limitations of the Google Drive app’s file provider and part of the reason why I added a built-in Google Drive client to Textastic in the first place.</p>

<h2 id="what-are-the-alternatives-to-google-drive">What are the alternatives to Google Drive?</h2>

<p>Textastic supports iCloud Drive sync by storing files in its <a href="https://www.textasticapp.com/v10/manual/managing_files/local_files_icloud.html">iCloud</a> location.</p>

<p>There are also clients for Dropbox, SFTP, FTP, and WebDAV.</p>

<p>You can find more information in the manual: <a href="https://www.textasticapp.com/v10/manual/remote_servers/index.html">Connecting to Remote Servers</a>.</p>

<h2 id="further-reading">Further Reading</h2>

<p>Other developers are in a similar situation:</p>

<ul>
  <li><a href="https://community.panels.app/t/google-drive-integration-removal/2056">Panels: Google Drive Integration Removal</a></li>
  <li><a href="https://www.ghisler.ch/board/viewtopic.php?t=80524">Total Commander: Google Drive access now only possible via own client id</a></li>
  <li><a href="https://moodle.org/mod/forum/discuss.php?d=453590">Moodle: Google Drive repo verification</a></li>
  <li><a href="https://www.googlecloudcommunity.com/gc/Workspace-Q-A/Drive-API-Auth-Scope-Changes-Handling-Changing-Remvoing-Scopes/m-p/674909">Google Workspace Forums: Drive API Auth Scope Changes</a></li>
  <li><a href="https://stackoverflow.com/questions/77740304/implementing-the-google-drive-file-picker-in-ios">Stack Overflow: Implementing the Google Drive File picker in iOS</a></li>
  <li><a href="https://www.reddit.com/r/androiddev/comments/1b483a6/end_of_google_drive_integration/">Reddit: End of Google Drive integration?</a></li>
  <li><a href="https://www.reddit.com/r/GoogleAppsScript/comments/199lnfx/i_gave_up_my_tier_2_casa_evaluation_this_torture/">Reddit: I gave up my Tier 2 CASA evaluation. This torture is too much for me.</a></li>
  <li><a href="https://issuetracker.google.com/issues/322267485">Google Issue Tracker: Google Drive Picker For iOS and Android</a></li>
</ul>]]></content><author><name>Alexander Blach</name><email>alexander@blach.io</email></author><category term="Textastic" /><category term="iPadOS" /><category term="iOS" /><summary type="html"><![CDATA[Google’s changes to the Google Drive API are forcing me to remove the built-in Google Drive client from Textastic for iOS/iPadOS.]]></summary></entry><entry><title type="html">Opening Git repository folders in Textastic 6.2</title><link href="https://blach.io/2016/08/02/opening-git-repository-folders-in-textastic-6-2/" rel="alternate" type="text/html" title="Opening Git repository folders in Textastic 6.2" /><published>2016-08-02T11:25:16+02:00</published><updated>2016-08-02T11:25:16+02:00</updated><id>https://blach.io/2016/08/02/opening-git-repository-folders-in-textastic-6-2</id><content type="html" xml:base="https://blach.io/2016/08/02/opening-git-repository-folders-in-textastic-6-2/"><![CDATA[<p>It is now possible to open entire folders from the iOS Git client <a href="https://workingcopyapp.com">Working Copy</a> in <a href="https://www.textasticapp.com">Textastic</a> using the <a href="https://developer.apple.com/library/ios/documentation/FileManagement/Conceptual/DocumentPickerProgrammingGuide/Introduction/Introduction.html">iOS document picker</a>. Previously you could only open individual files.</p>

<!-- more -->

<p>In this video you can see how this works:</p>

<div class="embed-container">
  <iframe src="https://www.youtube.com/embed/TA8atK2sdxc" width="700" height="480" frameborder="0" allowfullscreen="true">
  </iframe>
</div>

<p>These are the steps necessary to open a Git repository in Textastic 6.2:</p>

<ul>
  <li>Make sure <a href="https://workingcopyapp.com">Working Copy</a> is installed on your device.</li>
  <li>Tap on “Open…” in Textastic.</li>
  <li>Select “Working Copy”.<br />
<img src="/images/textastic_6_2_locations.png" alt="" width="569" /></li>
  <li>Navigate to an existing Git repository or clone/initialize a new one.</li>
  <li>Tap on “Pick” to open the repository.<br />
<img src="/images/textastic_6_2_pick.png" alt="" width="1024" /></li>
  <li>The repository is now added as an external folder below the “Open…” command.<br />
<img src="/images/textastic_6_2_external_folder.png" alt="" width="320" /></li>
</ul>

<p>The external folder can be used just as “Local Files” or “iCloud”: You can edit existing files and add new ones. You can download and upload files. Web preview is fully supported. Changes you make will be immediately shown in Working Copy. You can then commit your changes in Working Copy. This works great in Split View mode on the iPad.</p>

<p>Textastic and Working Copy are both available from the App Store:</p>

<ul>
  <li><a href="https://geo.itunes.apple.com/us/app/id1049254261?ct=blachio62&amp;at=11lNQP&amp;pt=15967&amp;mt=8">Textastic</a></li>
  <li><a href="https://geo.itunes.apple.com/us/app/working-copy/id896694807?ct=blachio62&amp;mt=8&amp;uo=6&amp;at=11lNQP">Working Copy</a></li>
</ul>]]></content><author><name>Alexander Blach</name><email>alexander@blach.io</email></author><category term="iOS" /><summary type="html"><![CDATA[Use Textastic to seamlessly open entire Git repositories from Working Copy as external folders.]]></summary></entry><entry><title type="html">Using Git on iOS with Working Copy and Textastic</title><link href="https://blach.io/2015/05/26/using-git-on-your-ipad-or-iphone-with-working-copy-and-textastic/" rel="alternate" type="text/html" title="Using Git on iOS with Working Copy and Textastic" /><published>2015-05-26T14:56:44+02:00</published><updated>2015-05-26T14:56:44+02:00</updated><id>https://blach.io/2015/05/26/using-git-on-your-ipad-or-iphone-with-working-copy-and-textastic</id><content type="html" xml:base="https://blach.io/2015/05/26/using-git-on-your-ipad-or-iphone-with-working-copy-and-textastic/"><![CDATA[<p>With the new document picker in iOS 8, you can use <a href="https://workingcopyapp.com">Working Copy</a> and <a href="https://www.textasticapp.com">Textastic</a> to fully access your Git repositories on your iPad or iPhone.</p>

<!-- more -->

<p><strong>Update:</strong> With Textastic 6.2, you can now <a href="/2016/08/02/opening-git-repository-folders-in-textastic-6-2/">open full Git repository folders from Working Copy</a> in addition to individual files.</p>

<p>In this video I demonstrate the workflow:</p>

<div class="embed-container">
  <iframe src="https://www.youtube.com/embed/RB1Blvi7K9I" width="700" height="480" frameborder="0" allowfullscreen="true">
  </iframe>
</div>

<p>In Working Copy, you can clone an existing repository from GitHub, BitBucket or your own private Git server. SSH, HTTPS and HTTP are fully supported. You can also create a new local repository in the app and push your changes to a remote server later.</p>

<p>Working Copy acts as an iOS 8 document provider, so that it appears as a location in the document picker next to iCloud Drive. It lets users open files directly from within another app like Textastic, editing them in place.</p>

<p><img src="/images/textastic_5_2_open_working_copy.png" alt="Open command in Textastic 5.2" width="250" align="right" /></p>

<p>In Textastic, you can invoke the document picker using the “Open…” command which was added in Textastic 5.2. In the menu that comes up, tap on “More” to enable Working Copy.</p>

<p>After you select “Working Copy”, you can see a list of all repositories that you cloned or created on your device. You can navigate through the folders in your repository and select the file you want to open. Changes you make to such a file are saved in Working Copy’s sandbox and you can immediately see a diff when you switch from Textastic to Working Copy. Once you are done, you can commit your changes and push the new commit to the remote server.</p>

<p>Using the “Recent Files” list in Textastic, you can quickly switch between your most recently opened external files without having to invoke the document picker.</p>

<p>Textastic and Working Copy are both available from the App Store:</p>

<ul>
  <li><a href="https://geo.itunes.apple.com/us/app/id1049254261?ct=blachiogit&amp;at=11lNQP&amp;pt=15967&amp;mt=8">Textastic</a></li>
  <li><a href="https://geo.itunes.apple.com/us/app/working-copy/id896694807?mt=8&amp;uo=6&amp;at=11lNQP">Working Copy</a></li>
</ul>]]></content><author><name>Alexander Blach</name><email>alexander@blach.io</email></author><category term="iOS" /><summary type="html"><![CDATA[Use Working Copy and Textastic on your iPad or iPhone to access your Git repositories, edit files and commit your changes.]]></summary></entry><entry><title type="html">Script to hide desktop icons and Dock when creating OS X screenshots</title><link href="https://blach.io/2014/10/25/script-to-hide-desktop-icons-and-dock-when-creating-os-x-screenshots/" rel="alternate" type="text/html" title="Script to hide desktop icons and Dock when creating OS X screenshots" /><published>2014-10-25T14:51:39+02:00</published><updated>2014-10-25T14:51:39+02:00</updated><id>https://blach.io/2014/10/25/script-to-hide-desktop-icons-and-dock-when-creating-os-x-screenshots</id><content type="html" xml:base="https://blach.io/2014/10/25/script-to-hide-desktop-icons-and-dock-when-creating-os-x-screenshots/"><![CDATA[<p>When creating screenshots for the latest version of <a href="https://www.textasticapp.com/mac.html">Textastic</a> for Mac in OS X Yosemite, I needed a way to quickly hide the Dock and all desktop icons without using a separate demo account on my Mac.</p>

<!-- more -->

<p>This is the resulting shell script <code class="language-plaintext highlighter-rouge">toggle_presentation_desktop.command</code>:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="c">#!/bin/bash</span>

<span class="k">if</span> <span class="o">[[</span> <span class="si">$(</span>defaults <span class="nb">read </span>com.apple.finder CreateDesktop<span class="si">)</span> <span class="o">=</span> 1 <span class="o">]]</span>
<span class="k">then
	</span><span class="nb">echo</span> <span class="s2">"enabling presentation mode"</span>
	defaults write com.apple.finder CreateDesktop <span class="nt">-bool</span> <span class="nb">false
	</span>osascript <span class="nt">-e</span> <span class="s2">"tell application </span><span class="se">\"</span><span class="s2">System Events</span><span class="se">\"</span><span class="s2"> to set the autohide of the dock preferences to true"</span>
	killall Finder
<span class="k">else
	</span><span class="nb">echo</span> <span class="s2">"disabling presentation mode"</span>
	defaults write com.apple.finder CreateDesktop <span class="nt">-bool</span> <span class="nb">true
	</span>osascript <span class="nt">-e</span> <span class="s2">"tell application </span><span class="se">\"</span><span class="s2">System Events</span><span class="se">\"</span><span class="s2"> to set the autohide of the dock preferences to false"</span>
	killall Finder
<span class="k">fi</span></code></pre></figure>

<p>Make the script executable:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nb">chmod</span> +x toggle_presentation_desktop.command</code></pre></figure>

<p>Setting the “CreateDesktop” default to false hides the desktop icons, but still displays the wallpaper. The script uses AppleScript to hide the Dock.</p>

<p>Now I can just use Spotlight to execute the <code class="language-plaintext highlighter-rouge">toggle_presentation_desktop.command</code> shell script and it will toggle the Dock and desktop icons.</p>

<p>I also used <a href="http://www.macbartender.com">Bartender</a> to hide all menu bar icons except Spotlight and Notification Center.</p>

<p>This is one of the resulting screenshots:</p>

<p><img src="/images/textastic_yosemite_screenshot_01.jpg" alt="" /></p>]]></content><author><name>Alexander Blach</name><email>alexander@blach.io</email></author><category term="Mac" /><summary type="html"><![CDATA[Easily hide unnecessary desktop elements when creating screenshots for Mac apps.]]></summary></entry><entry><title type="html">Generating App Store promo codes with itc.cli</title><link href="https://blach.io/2014/08/08/generating-app-store-promo-codes-with-itc-dot-cli/" rel="alternate" type="text/html" title="Generating App Store promo codes with itc.cli" /><published>2014-08-08T14:50:17+02:00</published><updated>2014-08-08T14:50:17+02:00</updated><id>https://blach.io/2014/08/08/generating-app-store-promo-codes-with-itc-dot-cli</id><content type="html" xml:base="https://blach.io/2014/08/08/generating-app-store-promo-codes-with-itc-dot-cli/"><![CDATA[<p>If you are like me and have an app available in versions for iPad, iPhone, and Mac, you know how tedious it is to create promo codes for the whole suite of apps. There needed to be a better way to quickly create a promo code for each app than the endless clicking and waiting game in iTunes Connect.</p>

<!-- more -->

<p><strong>Update May 26th, 2015:</strong> itc.cli does not work anymore. Please use <a href="https://github.com/fastlane/codes">codes</a> from the fastlane toolchain instead.</p>

<p><a href="https://github.com/kovpas/itc.cli">itc.cli</a> to the rescue! With the “iTunes Connect command line interface” it’s really easy to write a script that quickly generates a set of App Store promo codes.</p>

<h2 id="installing-itccli">Installing itc.cli</h2>
<p>First, we need to install itc.cli. The installation instructions on <a href="https://github.com/kovpas/itc.cli">itc.cli’s GitHub page</a> didn’t really work for me. Here’s what I did:</p>

<p>Install pip and itc.cli:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="c"># install Xcode command line tools (if necessary)</span>
xcode-select <span class="nt">--install</span>
<span class="c"># install pip</span>
<span class="nb">sudo </span>easy_install pip
<span class="c"># install itc.cli</span>
<span class="nb">sudo </span>pip <span class="nb">install </span>itc.cli</code></pre></figure>

<p>If you later want to upgrade itc.cli, do this:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nb">sudo </span>pip <span class="nb">install</span> <span class="nt">--upgrade</span> itc.cli</code></pre></figure>

<h2 id="script-to-generate-promo-codes-for-three-apps-at-once">Script to generate promo codes for three apps at once</h2>
<p>Now, it’s very easy to write a script that downloads one promo code for each app. You just need to know your iTunes Connect login and the Apple IDs of your apps. itc.cli lists all apps and their Apple IDs when you log in. Here’s a (slightly modified) example output:</p>

<figure class="highlight"><pre><code class="language-text" data-lang="text">itc login -u &lt;USERNAME&gt;
Password:
INFO - Login: logged in. Session cookies are saved to &lt;...&gt;
INFO - Application found: "Textastic Code Editor for iPad" (383577124)
INFO - Application found: "Textastic Code Editor for iPhone" (550156166)
INFO - Application found: "Textastic" (572491815)
INFO - Nothing to do.</code></pre></figure>

<p>With this information, I could write this <code class="language-plaintext highlighter-rouge">textastic_promo_all.command</code> script:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nb">echo</span> <span class="s2">"Textastic for iPad: "</span> <span class="o">&gt;&gt;</span> promocodes.txt
itc promo 1 <span class="nt">-a</span> 383577124 <span class="nt">-o</span> promocodes.txt <span class="nt">-u</span> &lt;USERNAME&gt;
<span class="nb">echo</span> <span class="s2">"Textastic for iPhone: "</span> <span class="o">&gt;&gt;</span> promocodes.txt
itc promo 1 <span class="nt">-a</span> 550156166 <span class="nt">-o</span> promocodes.txt <span class="nt">-u</span> &lt;USERNAME&gt;
<span class="nb">echo</span> <span class="s2">"Textastic for Mac: "</span> <span class="o">&gt;&gt;</span> promocodes.txt
itc promo 1 <span class="nt">-a</span> 572491815 <span class="nt">-o</span> promocodes.txt <span class="nt">-u</span> &lt;USERNAME&gt;</code></pre></figure>

<p>Make script executable:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nb">chmod</span> +x textastic_promo_all.command</code></pre></figure>

<p>Now you can just double-click on the <code class="language-plaintext highlighter-rouge">textastic_promo_all.command</code> file in Finder, enter your iTunes Connect password and it will automatically append three promo codes to a file called <code class="language-plaintext highlighter-rouge">promocodes.txt</code> - ready to send in an email.</p>]]></content><author><name>Alexander Blach</name><email>alexander@blach.io</email></author><category term="Mac" /><category term="iOS" /><summary type="html"><![CDATA[Easily request promo codes for several apps with just one click on a shell script.]]></summary></entry><entry><title type="html">NSJSONSerialization category to read JSON with comments</title><link href="https://blach.io/2014/07/28/nsjsonserialization-category-to-read-json-with-comments/" rel="alternate" type="text/html" title="NSJSONSerialization category to read JSON with comments" /><published>2014-07-28T21:09:02+02:00</published><updated>2014-07-28T21:09:02+02:00</updated><id>https://blach.io/2014/07/28/nsjsonserialization-category-to-read-json-with-comments</id><content type="html" xml:base="https://blach.io/2014/07/28/nsjsonserialization-category-to-read-json-with-comments/"><![CDATA[<p>Before Apple added NSJSONSerialization in iOS 5, I’ve been using JSONKit to parse commented JSON configuration files in <a href="https://www.textasticapp.com/">Textastic</a>. I’ve been wanting to replace it with NSJSONSerialization for some time now. The fact that JSONKit’s direct access of the <code class="language-plaintext highlighter-rouge">isa</code> pointer made Textastic crash on OS X 10.10 Yosemite finally made me do the switch.</p>

<!-- more -->

<p>The biggest hurdle was my use of <code class="language-plaintext highlighter-rouge">JKParseOptionComments</code>:</p>

<blockquote>
  <p>Allow C style <code class="language-plaintext highlighter-rouge">//</code> and <code class="language-plaintext highlighter-rouge">/* … */</code> comments in JSON. This is a fairly common extension to JSON, but JSON that contains C style comments is not strictly conforming JSON.</p>
</blockquote>

<p>Unfortunately, NSJSONSerialization doesn’t have an option to ignore comments in JSON files.</p>

<p>This is where my “<a href="https://github.com/blach/NSJSONSerialization-Comments">NSJSONSerialization+Comments</a>” category comes in!</p>

<p>You can use this category’s <code class="language-plaintext highlighter-rouge">JSONObjectWithCommentedData:options:error:</code> method just like NSJSONSerialization’s <code class="language-plaintext highlighter-rouge">JSONObjectWithData:options:error:</code>:</p>

<figure class="highlight"><pre><code class="language-objc" data-lang="objc"><span class="n">id</span> <span class="n">object</span> <span class="o">=</span> <span class="p">[</span><span class="n">NSJSONSerialization</span> <span class="nf">JSONObjectWithCommentedData</span><span class="p">:</span><span class="n">data</span> <span class="nf">options</span><span class="p">:</span><span class="mi">0</span> <span class="n">error</span><span class="o">:&amp;</span><span class="n">error</span><span class="p">];</span></code></pre></figure>

<p>The code is tuned for performance and works directly on UTF-8 data without converting it to an NSString. It strips single line and multi-line comments as well as whitespace before it hands over the data to NSJSONSerialization.</p>

<p>It also detects UTF-16 and UTF-32 through their byte order marks (BOM): if a non-UTF-8 BOM is found, it converts the data to UTF-8 using NSString. UTF-8 is definitely recommended if you don’t want this overhead.</p>

<p>I’ve also added a few convenience methods to load JSON from a file or URL instead of NSData.</p>

<p>More information can be found at the <a href="https://github.com/blach/NSJSONSerialization-Comments">NSJSONSerialization+Comments Github repository</a>.</p>]]></content><author><name>Alexander Blach</name><email>alexander@blach.io</email></author><category term="Mac" /><category term="iOS" /><summary type="html"><![CDATA[An Objective-C category that adds support for C style // and /* … */ comments to NSJSONSerialization.]]></summary></entry><entry><title type="html">Creating OS X document icons or: how to convert an icns file to png files</title><link href="https://blach.io/2013/03/11/creating-os-x-document-icons-or-how-to-convert-an-icns-file-to-png-files/" rel="alternate" type="text/html" title="Creating OS X document icons or: how to convert an icns file to png files" /><published>2013-03-11T11:45:00+01:00</published><updated>2013-03-11T11:45:00+01:00</updated><id>https://blach.io/2013/03/11/creating-os-x-document-icons-or-how-to-convert-an-icns-file-to-png-files</id><content type="html" xml:base="https://blach.io/2013/03/11/creating-os-x-document-icons-or-how-to-convert-an-icns-file-to-png-files/"><![CDATA[<p>While I was preparing version 1.0 of <a href="https://www.textasticapp.com/mac.html">Textastic for Mac</a>, one of the things I still needed to do was to create some basic document icons. Considering the amount of Mac apps out there, I was sure that either Apple or someone else would provide a template for that. Unfortunately, that doesn’t seem to be the case.</p>

<!-- more -->

<p>When Mac OS X came out, Apple seemingly provided a high-quality template for document icons in their <a href="http://mattgemmell.com/aqua-icon-kit/">Aqua Icon Kit</a>. According to <a href="http://forums.macrumors.com/showthread.php?t=377606">an old MacRumors thread</a>, a beta version of Icon Composer even included functionality to easily generate document icons.</p>

<p>Apple provides some useful information about creating proper document icons in the <a href="http://developer.apple.com/library/mac/#documentation/userexperience/conceptual/applehiguidelines/IconsImages/IconsImages.html#//apple_ref/doc/uid/20000967-TPXREF124">OS X Human Interface Guidelines</a>. But, they don’t link to any templates or tools you can use to ease the creation of them.</p>

<p>On <a href="http://stackoverflow.com/questions/3454201/mac-os-x-document-icon-template">Stack Overflow</a> I found that the generic document icon used by Mac OS X is located at <code class="force-wrap">/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/GenericDocument.icns</code>. One should be able to use this as the base for custom document icons.</p>

<p>So, now I needed a way to access the individual images in an <em>icns</em> file. Sure, you can open the file in Preview, but as soon as you try to copy and paste one of the images into Photoshop, you’ll notice that the pasted image doesn’t include an alpha channel and all transparency information is lost<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup>. This isn’t very helpful. There’s also <a href="http://www.macworld.com/article/1060156/sipsicns.html">the “sips” command line tool</a>, but it can only extract one <em>png</em> from the <em>icns</em> file or at least I don’t know how to make it extract all resolutions.</p>

<p>Thankfully, there is a solution if you have Xcode installed. Previously, you would create an <em>icns</em> file using the Icon Composer tool. The modern way, which also supports high-resolution icons for use with Retina screens, is to <a href="https://developer.apple.com/library/mac/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Optimizing/Optimizing.html#//apple_ref/doc/uid/TP40012302-CH7-SW8">let Xcode create an icns file automatically</a> from a set of <em>png</em> files in an iconset folder. Internally, Xcode uses the <code class="language-plaintext highlighter-rouge">iconutil</code> command line tool to create an <em>icns</em> file from an iconset folder. You can also <a href="https://developer.apple.com/library/mac/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Optimizing/Optimizing.html#//apple_ref/doc/uid/TP40012302-CH7-SW2">use the iconutil tool manually</a> and, even better: it also allows you to create an iconset folder with <em>png</em> files from an <em>icns</em> file!</p>

<p>Just use the following command:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>iconutil --convert iconset GenericDocument.icns
</code></pre></div></div>

<p>This will create a GenericDocument.iconset folder which contains all resolution variants as neatly named <em>png</em> files - ready to be customized by you.</p>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1" role="doc-endnote">
      <p>Update: This works for me now when I use Adobe Photoshop CC 2014 on Mavericks. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name>Alexander Blach</name><email>alexander@blach.io</email></author><category term="Mac" /><summary type="html"><![CDATA[How you can easily extract all images in an icns file to png files using iconutil on a Mac.]]></summary></entry></feed>