<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>Umur Gedik</title>
    <link href="https://umurgdk.dev/atom.xml" rel="self" type="application/atom+xml"/>
    <link href="https://umurgdk.dev"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2023-10-08T00:00:00+00:00</updated>
    <id>https://umurgdk.dev/atom.xml</id>
    <entry xml:lang="en">
        <title>Implementing Custom Controls With UIMenu in UIKit</title>
        <published>2023-10-08T00:00:00+00:00</published>
        <updated>2023-10-08T00:00:00+00:00</updated>
        <author>
          <name>Umur Gedik</name>
        </author>
        <link rel="alternate" href="https://umurgdk.dev/articles/implementing-custom-controls-with-menu-in-uikit/" type="text/html"/>
        <id>https://umurgdk.dev/articles/implementing-custom-controls-with-menu-in-uikit/</id>
        
        <content type="html">&lt;p&gt;Recently I was working on a client project with a custom control in a navigation bar to show the associated menu on tap. UIKit supports this behavior out of the box with &lt;code&gt;UIButton&lt;&#x2F;code&gt; when you associate an &lt;code&gt;UIMenu&lt;&#x2F;code&gt; and set it’s &lt;code&gt;showsMenuAsPrimaryAction&lt;&#x2F;code&gt;. &lt;&#x2F;p&gt;
&lt;div class=&quot;overlay-container&quot;&gt;
&lt;pre data-lang=&quot;swift&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-swift &quot;&gt;&lt;code class=&quot;language-swift&quot; data-lang=&quot;swift&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; button = UIButton(type: .system)
&lt;&#x2F;span&gt;&lt;span&gt;button.setTitle(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;Menu Button&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;for&lt;&#x2F;span&gt;&lt;span&gt;: .normal)
&lt;&#x2F;span&gt;&lt;span&gt;button.menu = UIMenu(
&lt;&#x2F;span&gt;&lt;span&gt;    children: [
&lt;&#x2F;span&gt;&lt;span&gt;        UIAction(
&lt;&#x2F;span&gt;&lt;span&gt;            title: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;Command 1&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;            handler: { _ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;in&lt;&#x2F;span&gt;&lt;span&gt; }
&lt;&#x2F;span&gt;&lt;span&gt;        )
&lt;&#x2F;span&gt;&lt;span&gt;    ]
&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;button.showsMenuAsPrimaryAction = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;true
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;video class=&quot;overlay-tr&quot; width=&quot;365&quot; autoplay loop playsinline disablepictureinpicture disableremoteplayback id=&quot;video-1&quot;&gt;
    &lt;source src=&quot;uibutton_menu.mp4&quot; type=&quot;video&#x2F;mp4&quot;&gt;
    &lt;source src=&quot;uibutton_menu.webm&quot; type=&quot;video&#x2F;webm&quot;&gt;
&lt;&#x2F;video&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;If all you need is a simple button with a menu, use &lt;code&gt;UIButton&lt;&#x2F;code&gt; by all means. If you want to have this behavior on your custom view it need to extend &lt;code&gt;UIControl&lt;&#x2F;code&gt; instead of &lt;code&gt;UIView&lt;&#x2F;code&gt;. Unfortunately there is no &lt;code&gt;.menu&lt;&#x2F;code&gt; property on &lt;code&gt;UIControl&lt;&#x2F;code&gt; class.&lt;&#x2F;p&gt;
&lt;p&gt;Another way to showing menus is adding an &lt;code&gt;UIContextMenuInteraction&lt;&#x2F;code&gt; to your view. But context menu interaction is triggered by long press gesture, and also it adds custom styling to your view while the long press gesture in progress. As the name suggests it is a context menu after all.&lt;&#x2F;p&gt;
&lt;div class=&quot;overlay-container&quot;&gt;
&lt;pre data-lang=&quot;swift&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-swift &quot;&gt;&lt;code class=&quot;language-swift&quot; data-lang=&quot;swift&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; label = UILabel()
&lt;&#x2F;span&gt;&lt;span&gt;label.text = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;A Label&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; interaction = UIContextMenuInteraction(delegate: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;label.addInteraction(interaction)
&lt;&#x2F;span&gt;&lt;span&gt;label.isUserInteractionEnabled = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;true
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;extension&lt;&#x2F;span&gt;&lt;span&gt; ViewController: UIContextMenuInteractionDelegate {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;func &lt;&#x2F;span&gt;&lt;span&gt;contextMenuInteraction(
&lt;&#x2F;span&gt;&lt;span&gt;        _ interaction: UIContextMenuInteraction,
&lt;&#x2F;span&gt;&lt;span&gt;        configurationForMenuAtLocation location: CGPoint
&lt;&#x2F;span&gt;&lt;span&gt;    ) -&amp;gt; UIContextMenuConfiguration? {
&lt;&#x2F;span&gt;&lt;span&gt;        UIContextMenuConfiguration(actionProvider: { suggestions &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;in
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; actions = [
&lt;&#x2F;span&gt;&lt;span&gt;                UIAction(
&lt;&#x2F;span&gt;&lt;span&gt;                    title: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;Command 1&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;                    handler: { _ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;                )
&lt;&#x2F;span&gt;&lt;span&gt;            ]
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return&lt;&#x2F;span&gt;&lt;span&gt; UIMenu(children: actions)
&lt;&#x2F;span&gt;&lt;span&gt;        })
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;video class=&quot;overlay-tr&quot; width=&quot;250&quot; autoplay loop playsinline disablepictureinpicture disableremoteplayback id=&quot;video-1&quot;&gt;
    &lt;source src=&quot;context_menu.mp4&quot; type=&quot;video&#x2F;mp4&quot;&gt;
    &lt;source src=&quot;context_menu.webm&quot; type=&quot;video&#x2F;webm&quot;&gt;
&lt;&#x2F;video&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;&lt;code&gt;UIControl&lt;&#x2F;code&gt; has a special treatment for &lt;code&gt;UIContextMenuInteraction&lt;&#x2F;code&gt;. If we extend our custom view from &lt;code&gt;UIControl&lt;&#x2F;code&gt; and enable context menu interaction via &lt;code&gt;isContextMenuInteractionEnabled&lt;&#x2F;code&gt; and &lt;code&gt;showsMenuAsPrimaryAction&lt;&#x2F;code&gt; we can achieve the same behavior as &lt;code&gt;UIButton&lt;&#x2F;code&gt; has. &lt;&#x2F;p&gt;
&lt;div class=&quot;overlay-container&quot;&gt;
&lt;pre data-lang=&quot;swift&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-swift &quot;&gt;&lt;code class=&quot;language-swift&quot; data-lang=&quot;swift&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;class&lt;&#x2F;span&gt;&lt;span&gt; CustomView: UIControl {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;func &lt;&#x2F;span&gt;&lt;span&gt;setupViews() {
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; label = UILabel()
&lt;&#x2F;span&gt;&lt;span&gt;        label.text = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;A Label&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;        addSubview(label)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; setup layout constraints...
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; Enable context menu interaction
&lt;&#x2F;span&gt;&lt;span&gt;        isContextMenuInteractionEnabled = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;true
&lt;&#x2F;span&gt;&lt;span&gt;        showsMenuAsPrimaryAction = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;true
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;lazy var&lt;&#x2F;span&gt;&lt;span&gt; menuConfig = UIContextMenuConfiguration(actionProvider: {
&lt;&#x2F;span&gt;&lt;span&gt;        suggestedActions &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;in
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; actions = [
&lt;&#x2F;span&gt;&lt;span&gt;            UIAction(
&lt;&#x2F;span&gt;&lt;span&gt;                title: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;Command 1&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;                handler: { _ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;in&lt;&#x2F;span&gt;&lt;span&gt; }
&lt;&#x2F;span&gt;&lt;span&gt;            )
&lt;&#x2F;span&gt;&lt;span&gt;        ]
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return&lt;&#x2F;span&gt;&lt;span&gt; UIMenu(children: actions)
&lt;&#x2F;span&gt;&lt;span&gt;    })
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;override func &lt;&#x2F;span&gt;&lt;span&gt;contextMenuInteraction(
&lt;&#x2F;span&gt;&lt;span&gt;        _ interaction: UIContextMenuInteraction,
&lt;&#x2F;span&gt;&lt;span&gt;        configurationForMenuAtLocation location: CGPoint
&lt;&#x2F;span&gt;&lt;span&gt;    ) -&amp;gt; UIContextMenuConfiguration? {
&lt;&#x2F;span&gt;&lt;span&gt;        menuConfig
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;video class=&quot;overlay-tr&quot; width=&quot;300&quot; autoplay loop playsinline disablepictureinpicture disableremoteplayback id=&quot;video-1&quot;&gt;
    &lt;source src=&quot;uicontrol_menu.mp4&quot; type=&quot;video&#x2F;mp4&quot;&gt;
    &lt;source src=&quot;uicontrol_menu.webm&quot; type=&quot;video&#x2F;webm&quot;&gt;
&lt;&#x2F;video&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;Keep in mind &lt;code&gt;UIControl&lt;&#x2F;code&gt; already conforms to &lt;code&gt;UIContextMenuInteractionDelegate&lt;&#x2F;code&gt; protocol, and &lt;code&gt;isContextMenuInteractionEnabled&lt;&#x2F;code&gt; property automatically adds &lt;code&gt;UIContextMenuInteraction&lt;&#x2F;code&gt; to the control. Make sure to check the &lt;a href=&quot;https:&#x2F;&#x2F;developer.apple.com&#x2F;documentation&#x2F;uikit&#x2F;uicontextmenuinteractiondelegate&quot;&gt;delegate protocol&lt;&#x2F;a&gt; for further customizations of the interaction.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Uploading files with URLSession using multipart requests</title>
        <published>2023-09-26T00:00:00+00:00</published>
        <updated>2023-09-26T00:00:00+00:00</updated>
        <author>
          <name>Umur Gedik</name>
        </author>
        <link rel="alternate" href="https://umurgdk.dev/articles/uploading-files-with-urlsession/" type="text/html"/>
        <id>https://umurgdk.dev/articles/uploading-files-with-urlsession/</id>
        
        <content type="html">&lt;p&gt;While working on my macOS Mastodon client Fil, I needed to upload media files to post statuses with images and videos attached. Mastodon API allows file uploads with &lt;code&gt;multipart&#x2F;form-data&lt;&#x2F;code&gt; encoded http request body. If you ever develop web applications with forms in it, this is what basically browsers do that when you have files in your forms by default. Encoding is pretty straight forward and a simple implementation in swift doesn’t takes more than 30 lines of code. So instead of including Alamofire in your next project just to support file uploads, you can write it yourself or copy paste the one I share in this post.&lt;&#x2F;p&gt;
&lt;p&gt;Multipart&#x2F;form-data requests consist of a magic &lt;strong&gt;boundary&lt;&#x2F;strong&gt; value and list of values (form fields) separated by that boundary in the body of the request. Boundary acts as a field separator, so that the server can understand where each field begins and ends. This is espacially important since these types of requests usually embeds binary data in the body of the request, so that simple new line characters like &lt;code&gt;\r\n&lt;&#x2F;code&gt; may not be sufficient.&lt;&#x2F;p&gt;
&lt;p&gt;A simple request representing two &lt;code&gt;String&lt;&#x2F;code&gt; fields (&lt;code&gt;title&lt;&#x2F;code&gt; and &lt;code&gt;description&lt;&#x2F;code&gt;) may look like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;http&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-http &quot;&gt;&lt;code class=&quot;language-http&quot; data-lang=&quot;http&quot;&gt;&lt;span&gt;POST &#x2F;upload&#x2F;image HTTP&#x2F;1.1
&lt;&#x2F;span&gt;&lt;span&gt;Host: api.example.com
&lt;&#x2F;span&gt;&lt;span&gt;Content-Type: multipart&#x2F;form-data; charset=utf-8; boundary=__MY_MAGIC_IDENTIFIER__
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;--__MY_MAGIC_IDENTIFIER
&lt;&#x2F;span&gt;&lt;span&gt;Content-Disposition: form-data; name=&amp;quot;title&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;My blog title
&lt;&#x2F;span&gt;&lt;span&gt;--__MY_MAGIC_IDENTIFIER
&lt;&#x2F;span&gt;&lt;span&gt;Content-Disposition: form-data; name=&amp;quot;description&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Some description about my blog
&lt;&#x2F;span&gt;&lt;span&gt;--__MY_MAGIC_IDENTIFIER--
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In this example &lt;code&gt;Content-Type&lt;&#x2F;code&gt; is set to &lt;code&gt;multipart&#x2F;form-data&lt;&#x2F;code&gt; with utf8 encoding and the boundary is defined as &lt;code&gt;__MY_MAGIC_IDENTIFIER__&lt;&#x2F;code&gt;, but you can choose your own identifier. In my app this is set to &lt;code&gt;__X_FIL_MULTIPART_BOUNDARY__&lt;&#x2F;code&gt;. Also the underscores are optional and stylistic in these examples.&lt;&#x2F;p&gt;
&lt;p&gt;Actual &lt;code&gt;httpBody&lt;&#x2F;code&gt; of the &lt;code&gt;URLRequest&lt;&#x2F;code&gt; starts just after the empty line after the headers. In this example the body starts with the &lt;strong&gt;boundary separator&lt;&#x2F;strong&gt;. Boundary separators are the magic boundary identifier prefixed with 2 dashes “&lt;code&gt;--&lt;&#x2F;code&gt;”. After the separator, we should define which field of the form data we are going to include with &lt;code&gt;Content-Disposition&lt;&#x2F;code&gt; attribute. It’s format self explanatory, and arguments (just like headers) are separated with “&lt;code&gt;;&lt;&#x2F;code&gt;” character. For string encoded fields this definition is sufficient, but for file fields, file name can be defined with &lt;code&gt;filename=&amp;quot;myfile.jpg&amp;quot;&lt;&#x2F;code&gt; argument.&lt;&#x2F;p&gt;
&lt;p&gt;After all the form fields &lt;code&gt;httpBody&lt;&#x2F;code&gt; should include a terminator to indicate there are no more data is provided. Terminator is the magic boundary identifier surrounded with 2 dashes “&lt;code&gt;--&lt;&#x2F;code&gt;” on both sides; like “&lt;code&gt;--__MY_MAGIC_IDENTIFIER__--&lt;&#x2F;code&gt;”. Make sure this terminator is only included at the end of the body, and do not put “&lt;code&gt;--&lt;&#x2F;code&gt;” at the end of the &lt;strong&gt;field separators&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;We can create a swift struct to abstract these details from our networking code. To start with supporting string fields:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;swift&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-swift &quot;&gt;&lt;code class=&quot;language-swift&quot; data-lang=&quot;swift&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; MultipartFormData.swift
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span&gt; MultipartFormData {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;public let&lt;&#x2F;span&gt;&lt;span&gt; boundary = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;__MY_MAGIC_IDENTIFIER__&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;private var&lt;&#x2F;span&gt;&lt;span&gt; data = Data()
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;public var&lt;&#x2F;span&gt;&lt;span&gt; contentType: String {
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;multipart&#x2F;form-data; charset=utf-8; boundary=&lt;&#x2F;span&gt;&lt;span&gt;\(boundary)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mutating func &lt;&#x2F;span&gt;&lt;span&gt;addString(_ value: String, forField field: String) {
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;var&lt;&#x2F;span&gt;&lt;span&gt; fieldString = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;--&lt;&#x2F;span&gt;&lt;span&gt;\(boundary)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;\r\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;        fieldString += &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;Content-Disposition: form-data; name=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;\(field)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;\&amp;quot;\r\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;        fieldString += &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;Content-Type: text&#x2F;plain; charset=utf-8&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;\r\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;        fieldString += &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;\r\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;        fieldString += &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;\(value)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;\r\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        data.append(fieldString.data(using: .utf8)!)
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mutating func &lt;&#x2F;span&gt;&lt;span&gt;makeBody() -&amp;gt; Data {
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; terminator = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;--&lt;&#x2F;span&gt;&lt;span&gt;\(boundary)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;--&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;        data.append(terminator.data(using: .utf8)!)
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return&lt;&#x2F;span&gt;&lt;span&gt; data
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As you may notice, instead of “&lt;code&gt;\n&lt;&#x2F;code&gt;” HTTP use “&lt;code&gt;\r\n&lt;&#x2F;code&gt;” for empty lines. Every field immediately starts with the &lt;strong&gt;boundary separator&lt;&#x2F;strong&gt; end ends with an empty line. And the &lt;strong&gt;terminator&lt;&#x2F;strong&gt; in the &lt;code&gt;makeBody&lt;&#x2F;code&gt; method does not includes an empty line at the end. We can use this helper with &lt;code&gt;URLSession&lt;&#x2F;code&gt; as:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;swift&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-swift &quot;&gt;&lt;code class=&quot;language-swift&quot; data-lang=&quot;swift&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;var&lt;&#x2F;span&gt;&lt;span&gt; formData = MultipartFormData()
&lt;&#x2F;span&gt;&lt;span&gt;formData.addString(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;Umur Gedik&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, forField: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;name&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;formData.addString(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;Turkey&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, forField: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;location&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;var&lt;&#x2F;span&gt;&lt;span&gt; req = URLRequest(url: myApiUrl)
&lt;&#x2F;span&gt;&lt;span&gt;req.setValue(formData.contentType, forHTTPHeaderField: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;Content-Type&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;req.httpBody = formData.makeBody()
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; (data, response) = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;try&lt;&#x2F;span&gt;&lt;span&gt; await URLSession.shared.data(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;for&lt;&#x2F;span&gt;&lt;span&gt;: req)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Adding support for file uploads are not that difficult. It requires an additional &lt;code&gt;Content-Type&lt;&#x2F;code&gt; attribute for the file field to let the server know what kind of file data we are sending. An example HTTP request including a file looks like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;http&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-http &quot;&gt;&lt;code class=&quot;language-http&quot; data-lang=&quot;http&quot;&gt;&lt;span&gt;POST &#x2F;upload&#x2F;image HTTP&#x2F;1.1
&lt;&#x2F;span&gt;&lt;span&gt;Host: api.example.com
&lt;&#x2F;span&gt;&lt;span&gt;Content-Type: multipart&#x2F;form-data; charset=utf-8; boundary=__MY_MAGIC_IDENTIFIER__
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;--__MY_MAGIC_IDENTIFIER
&lt;&#x2F;span&gt;&lt;span&gt;Content-Disposition: form-data; name=&amp;quot;name&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Umur Gedik
&lt;&#x2F;span&gt;&lt;span&gt;--__MY_MAGIC_IDENTIFIER
&lt;&#x2F;span&gt;&lt;span&gt;Content-Disposition: form-data; name=&amp;quot;avatar&amp;quot;; filename=&amp;quot;avatar.jpg&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;Content-Type: image&#x2F;jpeg
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;BINARY JPEG DATA IS NOT SHOWN HERE&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;--__MY_MAGIC_IDENTIFIER--
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Implementation in our &lt;code&gt;MultipartFormData&lt;&#x2F;code&gt; should append the given &lt;code&gt;Data&lt;&#x2F;code&gt; as it is to the body after the separator and the &lt;code&gt;Content-Disposition&lt;&#x2F;code&gt; like:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;swift&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-swift &quot;&gt;&lt;code class=&quot;language-swift&quot; data-lang=&quot;swift&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; MultipartFormData.swift
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span&gt; MultipartFormData {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; ...
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mutating func &lt;&#x2F;span&gt;&lt;span&gt;addFile(named name: String, data fileData: Data, mimeType: String, forField field: String) {
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;var&lt;&#x2F;span&gt;&lt;span&gt; fieldString = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;--&lt;&#x2F;span&gt;&lt;span&gt;\(boundary)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;\r\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; Here we add filename as well
&lt;&#x2F;span&gt;&lt;span&gt;        fieldString += &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;Content-Disposition: form-data; name=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;\(field)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;; filename=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;\(name)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;\&amp;quot;\r\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;        fieldString += &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;Content-Type: &lt;&#x2F;span&gt;&lt;span&gt;\(mimeType)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;\r\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;        fieldString += &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;\r\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        data.append(fieldString.data(using: .utf8)!)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; we append the given file data as it is immediately after the details
&lt;&#x2F;span&gt;&lt;span&gt;        data.append(fileData)
&lt;&#x2F;span&gt;&lt;span&gt;        data.append(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;\r\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;.data(using: .utf8)!)
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; ...
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;addFile&lt;&#x2F;code&gt; method introduces &lt;code&gt;filename&lt;&#x2F;code&gt; and &lt;code&gt;mimeType&lt;&#x2F;code&gt; to inform the server about the details of our file to upload. &lt;code&gt;mimeType&lt;&#x2F;code&gt; can be found by &lt;code&gt;UTType&lt;&#x2F;code&gt; in &lt;code&gt;UniformTypeIdentifiers&lt;&#x2F;code&gt; module. Example usage may look like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;swift&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-swift &quot;&gt;&lt;code class=&quot;language-swift&quot; data-lang=&quot;swift&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;UniformTypeIdentifiers
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;var&lt;&#x2F;span&gt;&lt;span&gt; formData = MultipartFormData()
&lt;&#x2F;span&gt;&lt;span&gt;formData.addString(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;Umur Gedik&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, forField: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;name&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;formData.addString(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;Turkey&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, forField: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;location&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; assuming we have a file URL
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; data = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;try&lt;&#x2F;span&gt;&lt;span&gt; Data(contentsOf: fileURL)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; typeIdentifier = UTType(filenameExtension: url.pathExtension)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; mimeType = typeIdentifier.preferredMIMEType
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;formData.addFile(named: fileURL.lastPathComponent, data: data, mimeType: mimeType, forField: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;avatar&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;var&lt;&#x2F;span&gt;&lt;span&gt; req = URLRequest(url: myApiUrl)
&lt;&#x2F;span&gt;&lt;span&gt;req.setValue(formData.contentType, forHTTPHeaderField: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;Content-Type&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;req.httpBody = formData.makeBody()
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; (data, response) = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;try&lt;&#x2F;span&gt;&lt;span&gt; await URLSession.shared.data(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;for&lt;&#x2F;span&gt;&lt;span&gt;: req)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;For the reference here is the full implementation of our &lt;code&gt;MultipartFormData&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;swift&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-swift &quot;&gt;&lt;code class=&quot;language-swift&quot; data-lang=&quot;swift&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; MultipartFormData.swift
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span&gt; MultipartFormData {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;public let&lt;&#x2F;span&gt;&lt;span&gt; boundary = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;__MY_MAGIC_IDENTIFIER__&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;private var&lt;&#x2F;span&gt;&lt;span&gt; data = Data()
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;public var&lt;&#x2F;span&gt;&lt;span&gt; contentType: String {
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;multipart&#x2F;form-data; charset=utf-8; boundary=&lt;&#x2F;span&gt;&lt;span&gt;\(boundary)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mutating func &lt;&#x2F;span&gt;&lt;span&gt;addString(_ value: String, forField field: String) {
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;var&lt;&#x2F;span&gt;&lt;span&gt; fieldString = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;--&lt;&#x2F;span&gt;&lt;span&gt;\(boundary)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;\r\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;        fieldString += &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;Content-Disposition: form-data; name=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;\(field)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;\&amp;quot;\r\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;        fieldString += &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;Content-Type: text&#x2F;plain; charset=utf-8&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;\r\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;        fieldString += &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;\r\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;        fieldString += &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;\(value)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;\r\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        data.append(fieldString.data(using: .utf8)!)
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mutating func &lt;&#x2F;span&gt;&lt;span&gt;addFile(named name: String, data fileData: Data, mimeType: String, forField field: String) {
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;var&lt;&#x2F;span&gt;&lt;span&gt; fieldString = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;--&lt;&#x2F;span&gt;&lt;span&gt;\(boundary)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;\r\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; Here we add filename as well
&lt;&#x2F;span&gt;&lt;span&gt;        fieldString += &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;Content-Disposition: form-data; name=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;\(field)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;; filename=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;\(name)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;\&amp;quot;\r\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;        fieldString += &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;Content-Type: &lt;&#x2F;span&gt;&lt;span&gt;\(mimeType)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;\r\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;        fieldString += &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;\r\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        data.append(fieldString.data(using: .utf8)!)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; we append the given file data as it is immediately after the details
&lt;&#x2F;span&gt;&lt;span&gt;        data.append(fileData)
&lt;&#x2F;span&gt;&lt;span&gt;        data.append(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;\r\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;.data(using: .utf8)!)
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mutating func &lt;&#x2F;span&gt;&lt;span&gt;makeBody() -&amp;gt; Data {
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; terminator = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;quot;--&lt;&#x2F;span&gt;&lt;span&gt;\(boundary)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;--&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;        data.append(terminator.data(using: .utf8)!)
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return&lt;&#x2F;span&gt;&lt;span&gt; data
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Distribute macOS Applications as DMG Images</title>
        <published>2023-09-11T00:00:00+00:00</published>
        <updated>2023-09-11T00:00:00+00:00</updated>
        <author>
          <name>Umur Gedik</name>
        </author>
        <link rel="alternate" href="https://umurgdk.dev/articles/distribute-macos-applications-as-dmg-images/" type="text/html"/>
        <id>https://umurgdk.dev/articles/distribute-macos-applications-as-dmg-images/</id>
        
        <content type="html">&lt;p&gt;Distributing apps as  &lt;code&gt;.dmg&lt;&#x2F;code&gt; files requires the developer to sign the &lt;code&gt;.dmg&lt;&#x2F;code&gt; file with a Developer ID Application certificate and notarizing it.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;prerequirements&quot;&gt;Prerequirements&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;A provisioning profile and certificate with type  Developer ID Application&lt;&#x2F;li&gt;
&lt;li&gt;https:&#x2F;&#x2F;developer.apple.com &amp;gt; Account &amp;gt; Certificates, IDs &amp;amp; Profiles &amp;gt; Profiles&lt;&#x2F;li&gt;
&lt;li&gt;Install the certificate in your Keychain (double clicking the certificate file will install)&lt;&#x2F;li&gt;
&lt;li&gt;Make sure you use the correct provisioning profile to build your archive&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;archiving&quot;&gt;Archiving&lt;&#x2F;h2&gt;
&lt;p&gt;Archive your application in Xcode by Product &amp;gt; Archive. When archive build is complete Xcode will open a window called &lt;strong&gt;Organizer&lt;&#x2F;strong&gt; (Xcode menu Window &amp;gt; Organizer) where you can sign and export your  &lt;code&gt;.app&lt;&#x2F;code&gt; file.&lt;&#x2F;p&gt;
&lt;p&gt;Click  Distribute App and then select  Developer ID as your method of distribution. In the next screen select &lt;strong&gt;Export&lt;&#x2F;strong&gt; (sign without notarization) as your destination, we will notarize the &lt;code&gt;.dmg&lt;&#x2F;code&gt; file not the &lt;code&gt;.app&lt;&#x2F;code&gt; export.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;creating-dmg&quot;&gt;Creating DMG&lt;&#x2F;h2&gt;
&lt;ol&gt;
&lt;li&gt;You can use &lt;strong&gt;Disk Utilities&lt;&#x2F;strong&gt; app in your mac to create an empty  &lt;code&gt;.sparsebundle&lt;&#x2F;code&gt; disk image&lt;&#x2F;li&gt;
&lt;li&gt;Mount the disk image (double-click) and open the volume (should be listed at Finder’s sidebar)&lt;&#x2F;li&gt;
&lt;li&gt;Configure the display options of the finder like; show as icons, icon size, snap to grid, and background.&lt;&#x2F;li&gt;
&lt;li&gt;Don’t forget to create a link to  &lt;code&gt;&#x2F;Applications&lt;&#x2F;code&gt; directory to easy drag n drop install&lt;&#x2F;li&gt;
&lt;li&gt;Close the finder window when it looks good&lt;&#x2F;li&gt;
&lt;li&gt;Get back to &lt;strong&gt;Disk Utility&lt;&#x2F;strong&gt; app and show select &lt;strong&gt;Show All Devices&lt;&#x2F;strong&gt; from the sidebar icon&lt;&#x2F;li&gt;
&lt;li&gt;On the sidebar find the mounted sparsebundle image&lt;&#x2F;li&gt;
&lt;li&gt;Right-Click and select create image on the  container and choose compressed and save as .dmg&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;signing-and-notarizing&quot;&gt;Signing and Notarizing&lt;&#x2F;h2&gt;
&lt;p&gt;First we need to sign  &lt;code&gt;.dmg&lt;&#x2F;code&gt; file just like the  &lt;code&gt;.app&lt;&#x2F;code&gt;. These commands doesn’t produce any output when it is successfull.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;# Sign the .dmg file with the certificate mentioned in the prerequirements section
&lt;&#x2F;span&gt;&lt;span&gt;$ codesign --sign &amp;quot;Developer ID Application: &amp;lt;Your Name&amp;gt; (Team ID)&amp;quot; path&#x2F;to&#x2F;application.dmg
&lt;&#x2F;span&gt;&lt;span&gt;$ codesign --verify path&#x2F;to&#x2F;application.dmg
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;To notarize the &lt;code&gt;.dmg&lt;&#x2F;code&gt; we need to run  notarytool. notary tool requires either AppStoreConnect API Key or an application specific password. As you may guessed API key can be obtained from App Store Connect page. Application specific password can be created at Apple ID.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;# If you are using application specific password
&lt;&#x2F;span&gt;&lt;span&gt;$ xcrun notarytool submit --wait --apple-id &amp;quot;&amp;lt;apple-id-email&amp;gt;&amp;quot; --password &amp;quot;&amp;lt;app-specific-password&amp;gt;&amp;quot; --team-id TEAM_ID MyApp.dmg
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;# If you are using API key
&lt;&#x2F;span&gt;&lt;span&gt;$ xcrun notarytool submit --wait --key &amp;lt;path-to-key-file&amp;gt; --key-id &amp;lt;10 char key id&amp;gt; --issuer &amp;lt;issuer id UUID&amp;gt; MyApp.dmg
&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; Successfully received submission info
&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;   createdDate: 2023-09-11T19:38:24.532Z
&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;   id: 4667a4a7-xxxx-xxxx-xxxx-d83eb3124f84
&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;   name: MyApp.dmg
&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;   status: Accepted
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;# If you don&amp;#39;t want to wait until the notarization complete ommit --wait parameter
&lt;&#x2F;span&gt;&lt;span&gt;# In that case output will contain the submit ID you can use that ID to query
&lt;&#x2F;span&gt;&lt;span&gt;# the status of the notarization
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After the notarization is complete and status is &lt;strong&gt;Accepted&lt;&#x2F;strong&gt;, &lt;code&gt;.dmg&lt;&#x2F;code&gt; file needs to be stapled. Apple notarization process creates a ticket after a successful submit. To attach that ticket to our application (in this case our .dmg file):&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;$ xcrun stapler staple MyApp.dmg
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;# To test signing &amp;amp; notarization is successful
&lt;&#x2F;span&gt;&lt;span&gt;$ spctl -a -t open --context context:primary-signature -v MyApp.dmg
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; MyApp.dmg: accepted
&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; source=Notarized Developer ID
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If the output from  &lt;code&gt;spctl&lt;&#x2F;code&gt; command is different (as in rejected) you maybe skip a step, please make sure everything is done in order.&lt;&#x2F;p&gt;
&lt;p&gt;Happy deployments!&lt;&#x2F;p&gt;
</content>
        
    </entry>
</feed>
