<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/"><channel><title>Swift Package Manager – IMG.LY Blog</title><description>Posts tagged Swift Package Manager on the IMG.LY blog.</description><link>https://img.ly/blog/tag/swift-package-manager/</link><language>en-us</language><image><url>https://img.ly/apple-touch-icon.png</url><title>Swift Package Manager – IMG.LY Blog</title><link>https://img.ly/blog/tag/swift-package-manager/</link></image><atom:link href="https://img.ly/blog/tag/swift-package-manager/rss.xml" rel="self" type="application/rss+xml"/><generator>Astro</generator><lastBuildDate>Fri, 02 Oct 2026 15:22:17 GMT</lastBuildDate><ttl>60</ttl><item><title>How to integrate a Photo Editor into your iOS App</title><link>https://img.ly/blog/how-to-integrate-a-photo-editor-into-your-ios-app-ced008a7088b/</link><guid isPermaLink="true">https://img.ly/blog/how-to-integrate-a-photo-editor-into-your-ios-app-ced008a7088b/</guid><description>Add a photo editor to an iOS app with CE.SDK and Swift Package Manager</description><pubDate>Wed, 10 Jul 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In this tutorial, we’re going to add a photo editor to an iOS app using the CreativeEditor SDK. We’re going to use Xcode, Swift Package Manager, and the Photo Editor starter kit, a complete Xcode project that opens straight into the editor. By the end we’ll have an app whose editor opens on the kit’s blank page, with crop, filters and a share sheet already wired up, and a dock button that pulls a photo in off the device.&lt;/p&gt;
&lt;p&gt;Because the starter kit is an entire Xcode project, there are two ways in. We can clone it and run it as it stands, which is the quickest way to see the editor working. Or we can copy its files into an app we already have. We’ll do both, starting with the clone.&lt;/p&gt;
&lt;h2 id=&quot;what-we-need&quot;&gt;What we need&lt;/h2&gt;
&lt;p&gt;A Mac with a recent version of Xcode, and an app with a deployment target of iOS 16.0 or later. The &lt;code&gt;IMGLYUI-swift&lt;/code&gt; package declares &lt;code&gt;// swift-tools-version:6.3.1&lt;/code&gt; on the first line of its manifest, which is the line Swift Package Manager reads before anything else, so an older toolchain refuses the package outright. Swift 6.3.1 is the floor.&lt;/p&gt;
&lt;p&gt;We don’t need a license key to follow along. Without one, the editor runs in evaluation mode with a watermark.&lt;/p&gt;
&lt;h2 id=&quot;running-the-starter-kit&quot;&gt;Running the starter kit&lt;/h2&gt;
&lt;p&gt;The Photo Editor starter kit lives in its own repository, with a branch for the SDK release we want. That is 1.82.1 here:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;git&lt;/span&gt;&lt;span&gt; clone&lt;/span&gt;&lt;span&gt; -b&lt;/span&gt;&lt;span&gt; v1.82.1&lt;/span&gt;&lt;span&gt; https://github.com/imgly/starterkit-photo-editor-ios.git&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;cd&lt;/span&gt;&lt;span&gt; starterkit-photo-editor-ios&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we open the project in Xcode, select a simulator, and press Run. Xcode resolves the Swift package dependencies on the first build, and that first resolve takes a while: the engine framework is a compressed download of about 390 MB. The archive carries simulator and device slices along with debug symbols, so a shipped app doesn’t grow by anything like that much, and the &lt;a href=&quot;https://img.ly/docs/cesdk/ios/bundle-size-df9210/&quot;&gt;Bundle Size&lt;/a&gt; guide has the numbers. It’s still a long first coffee.&lt;/p&gt;
&lt;p&gt;The cloned project’s &lt;code&gt;Secrets.swift&lt;/code&gt; ships an empty license key, which is what puts it in evaluation mode. That’s enough for everything below.&lt;/p&gt;
&lt;h2 id=&quot;adding-the-editor-to-an-existing-app&quot;&gt;Adding the editor to an existing app&lt;/h2&gt;
&lt;p&gt;Most of the time we’re not starting from an empty project. Two steps get the editor into an app we already have: the package, then the starter kit files.&lt;/p&gt;
&lt;p&gt;In Xcode, we use &lt;code&gt;File &gt; Add Package Dependencies...&lt;/code&gt; and paste this URL into the search field at the top right of the modal:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;https://github.com/imgly/IMGLYUI-swift&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When the package information appears, we select version 1.82.1 and add the &lt;code&gt;IMGLYEditor&lt;/code&gt; product to our app target. There’s also an umbrella library, &lt;code&gt;IMGLYUI&lt;/code&gt;, which pulls in every UI module at once and is the convenient thing to add while we’re exploring. Before releasing, cut it back to the libraries we actually import, which helps conserve app space.&lt;/p&gt;
&lt;p&gt;The second step is the starter kit itself. Its files live in our own codebase, which is what makes the editor’s behavior something we can edit. We pull the &lt;code&gt;StarterKit&lt;/code&gt; folder out of the v1.82.1 branch archive:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;repo&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;starterkit-photo-editor-ios&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;version&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;1.82.1&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;curl&lt;/span&gt;&lt;span&gt; -L&lt;/span&gt;&lt;span&gt; &quot;https://codeload.github.com/imgly/${&lt;/span&gt;&lt;span&gt;repo&lt;/span&gt;&lt;span&gt;}/tar.gz/refs/heads/v${&lt;/span&gt;&lt;span&gt;version&lt;/span&gt;&lt;span&gt;}&quot;&lt;/span&gt;&lt;span&gt; |&lt;/span&gt;&lt;span&gt; tar&lt;/span&gt;&lt;span&gt; -xz&lt;/span&gt;&lt;span&gt; --strip-components=1&lt;/span&gt;&lt;span&gt; &quot;${&lt;/span&gt;&lt;span&gt;repo&lt;/span&gt;&lt;span&gt;}-${&lt;/span&gt;&lt;span&gt;version&lt;/span&gt;&lt;span&gt;}/StarterKit&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then we drag the &lt;code&gt;StarterKit&lt;/code&gt; folder into the Xcode project. Here it’s essential that “Copy items if needed” is checked, so the files are copied into the project instead of just being referenced, and that they’re added to the app target. &lt;code&gt;photo-ui-empty.png&lt;/code&gt; comes along with them and has to show up under Copy Bundle Resources, because the editor looks it up in the app bundle at startup.&lt;/p&gt;
&lt;p&gt;Here’s what the folder holds:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;StarterKit/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;├── PhotoEditorStarterKit.swift         # SwiftUI view that launches the editor&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;├── PhotoEditorConfiguration.swift      # Editor configuration (callbacks + UI components)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;├── photo-ui-empty.png                  # The image the editor opens with&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;├── callbacks/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;│   ├── OnCreate+Photo.swift            # Editor initialization logic&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;│   ├── OnExport+Photo.swift            # Export flow and handling&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;│   ├── OnLoaded+Photo.swift            # Post-load setup (crop behavior)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;│   └── OnChanged+Photo.swift           # Edit mode change handling&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;├── components/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;│   ├── CanvasMenu+Photo.swift          # Canvas menu configuration&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;│   ├── Dock+Photo.swift                # Dock configuration&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;│   ├── InspectorBar+Photo.swift        # Inspector bar configuration&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;│   └── NavigationBar+Photo.swift       # Navigation bar configuration&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;└── examples/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    └── ExampleForceCrop.swift          # Optional force-crop example&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;putting-the-editor-on-screen&quot;&gt;Putting the editor on screen&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;PhotoEditorStarterKit.swift&lt;/code&gt; is the view that shows the editor. It builds an &lt;code&gt;EngineSettings&lt;/code&gt; value and hands it to the &lt;code&gt;Editor&lt;/code&gt; view together with a configuration:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;swift&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; IMGLYEditor&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; IMGLYEngine&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; SwiftUI&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;struct&lt;/span&gt;&lt;span&gt; PhotoEditorStarterKit&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;View &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // Provide `EngineSettings` with your license and an optional userId.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  let&lt;/span&gt;&lt;span&gt; settings &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; EngineSettings&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    license&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;nil&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;// Use nil for evaluation mode with watermark&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    userID&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;&amp;#x3C;your unique user id&gt;&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  var&lt;/span&gt;&lt;span&gt; body: &lt;/span&gt;&lt;span&gt;some&lt;/span&gt;&lt;span&gt; View {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    Editor&lt;/span&gt;&lt;span&gt;(settings)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      .imgly.&lt;/span&gt;&lt;span&gt;configuration&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        PhotoEditorConfiguration&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As the file ships, that &lt;code&gt;license:&lt;/code&gt; line reads &lt;code&gt;secrets.licenseKey&lt;/code&gt;. &lt;code&gt;Secrets.swift&lt;/code&gt; lives in &lt;code&gt;StarterKit-PhotoEditor/&lt;/code&gt;, which the extract above leaves behind, so the clone compiles and the copied folder does not until the line is replaced. Passing &lt;code&gt;nil&lt;/code&gt; puts the editor in evaluation mode, which is where we want it until we’ve got a key of our own. The &lt;code&gt;userID&lt;/code&gt; is optional and ties an editing session to our own user record, which is what makes the monthly active user count come out right when the same person uses the app on two devices.&lt;/p&gt;
&lt;p&gt;The editor puts its close button in the leading slot of a navigation bar, and undo, redo, a preview toggle and export in the trailing one, so the view has to sit inside a navigation container. The sample app’s &lt;code&gt;ContentView&lt;/code&gt; does that and nothing else:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;swift&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; SwiftUI&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;struct&lt;/span&gt;&lt;span&gt; ContentView&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;View &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  var&lt;/span&gt;&lt;span&gt; body: &lt;/span&gt;&lt;span&gt;some&lt;/span&gt;&lt;span&gt; View {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    NavigationStack&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      PhotoEditorStarterKit&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That file sits in &lt;code&gt;StarterKit-PhotoEditor/&lt;/code&gt;, so it is not one of the twelve we extracted. In an app we already have, we write the same wrapper ourselves, or push &lt;code&gt;PhotoEditorStarterKit()&lt;/code&gt; onto a navigation stack that is already on screen.&lt;/p&gt;
&lt;p&gt;Without a &lt;code&gt;NavigationStack&lt;/code&gt; or some other navigation context somewhere above it, the toolbars come up missing.&lt;/p&gt;
&lt;h2 id=&quot;the-tools-the-user-gets&quot;&gt;The tools the user gets&lt;/h2&gt;
&lt;p&gt;The dock along the bottom of the canvas is the list of tools, and it’s spelled out in &lt;code&gt;components/Dock+Photo.swift&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;swift&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;builder.&lt;/span&gt;&lt;span&gt;items&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;span&gt;_&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  Dock.Buttons.&lt;/span&gt;&lt;span&gt;adjustments&lt;/span&gt;&lt;span&gt;() &lt;/span&gt;&lt;span&gt;// Image adjustments&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  Dock.Buttons.&lt;/span&gt;&lt;span&gt;filter&lt;/span&gt;&lt;span&gt;() &lt;/span&gt;&lt;span&gt;// Filters&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  Dock.Buttons.&lt;/span&gt;&lt;span&gt;effect&lt;/span&gt;&lt;span&gt;() &lt;/span&gt;&lt;span&gt;// Effects&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  Dock.Buttons.&lt;/span&gt;&lt;span&gt;blur&lt;/span&gt;&lt;span&gt;() &lt;/span&gt;&lt;span&gt;// Blur&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  Dock.Buttons.&lt;/span&gt;&lt;span&gt;crop&lt;/span&gt;&lt;span&gt;() &lt;/span&gt;&lt;span&gt;// Crop tool&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  Dock.Buttons.&lt;/span&gt;&lt;span&gt;textLibrary&lt;/span&gt;&lt;span&gt;() &lt;/span&gt;&lt;span&gt;// Text tools&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  Dock.Buttons.&lt;/span&gt;&lt;span&gt;shapesLibrary&lt;/span&gt;&lt;span&gt;() &lt;/span&gt;&lt;span&gt;// Shapes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  Dock.Buttons.&lt;/span&gt;&lt;span&gt;stickersLibrary&lt;/span&gt;&lt;span&gt;() &lt;/span&gt;&lt;span&gt;// Stickers&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;items&lt;/code&gt; sets the contents of the dock, replacing whatever was there, so this list is the dock. Delete a line and that tool’s gone. Adding a line is how the photo roll button arrives further down.&lt;/p&gt;
&lt;h2 id=&quot;the-image-the-editor-opens&quot;&gt;The image the editor opens&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;callbacks/OnCreate+Photo.swift&lt;/code&gt; decides what’s on the canvas when the editor appears. Its &lt;code&gt;defaultCreateScene&lt;/code&gt; callback loads the blank placeholder PNG that travels with the kit:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;swift&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; SWIFT_PACKAGE&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  let&lt;/span&gt;&lt;span&gt; bundle &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; Bundle.module&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;span&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  let&lt;/span&gt;&lt;span&gt; bundle &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; Bundle&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;for&lt;/span&gt;&lt;span&gt;: PhotoEditorConfiguration.&lt;/span&gt;&lt;span&gt;self&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;span&gt;endif&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; imageURL &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; bundle.&lt;/span&gt;&lt;span&gt;url&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;forResource&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;photo-ui-empty&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;withExtension&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;png&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;try&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; engine.scene.&lt;/span&gt;&lt;span&gt;create&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;fromImage&lt;/span&gt;&lt;span&gt;: imageURL)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;Bundle(for:)&lt;/code&gt; branch is the one that applies when the kit has been added to an app target the way we did it; &lt;code&gt;Bundle.module&lt;/code&gt; applies when it compiles inside a Swift package. To open one of our users’ own photos, point &lt;code&gt;engine.scene.create(fromImage:)&lt;/code&gt; at that file instead.&lt;/p&gt;
&lt;p&gt;A second callback in the same file, &lt;code&gt;defaultLoadAssetSources&lt;/code&gt;, registers the device’s photo library as an asset source. That registration is its last line:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;swift&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;try&lt;/span&gt;&lt;span&gt; engine.asset.&lt;/span&gt;&lt;span&gt;addSource&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;PhotoRollAssetSource&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;engine&lt;/span&gt;&lt;span&gt;: engine))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Registering the source is half the job. Nothing in the editor opens the library until the dock carries a button for it, and the eight buttons we printed above don’t include one, so we add a ninth line to &lt;code&gt;Dock+Photo.swift&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;swift&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Dock.Buttons.&lt;/span&gt;&lt;span&gt;photoRoll&lt;/span&gt;&lt;span&gt;() &lt;/span&gt;&lt;span&gt;// Photos from the device&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A tap on that button now opens the system photos picker, and the chosen photo goes into the design. The picker runs out of process and the user grants access one selection at a time, so no permission prompt of ours appears and the kit needs no privacy keys in &lt;code&gt;Info.plist&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To let people browse their whole library inside the editor, register the source with full library access. The button stays as it is, and only the mode changes:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;swift&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;try&lt;/span&gt;&lt;span&gt; engine.asset.&lt;/span&gt;&lt;span&gt;addSource&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;PhotoRollAssetSource&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;engine&lt;/span&gt;&lt;span&gt;: engine, &lt;/span&gt;&lt;span&gt;mode&lt;/span&gt;&lt;span&gt;: .fullLibraryAccess))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That mode reads the library directly, so iOS does want a usage description. Without this key in &lt;code&gt;Info.plist&lt;/code&gt;, the system terminates the app the first time the library is touched:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;xml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span&gt;&gt;NSPhotoLibraryUsageDescription&amp;#x3C;/&lt;/span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&gt;Grant access to your photo library to add photos and videos to your designs.&amp;#x3C;/&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;getting-the-picture-back-out&quot;&gt;Getting the picture back out&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;callbacks/OnExport+Photo.swift&lt;/code&gt; runs when the user taps export. It writes a PNG to a temporary file and hands that file to the system share sheet:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;swift&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;guard&lt;/span&gt;&lt;span&gt; let&lt;/span&gt;&lt;span&gt; scene &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; try&lt;/span&gt;&lt;span&gt; engine.scene.&lt;/span&gt;&lt;span&gt;get&lt;/span&gt;&lt;span&gt;() &lt;/span&gt;&lt;span&gt;else&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  throw&lt;/span&gt;&lt;span&gt; EditorError&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;No scene was found.&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; data &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; try&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; engine.block.&lt;/span&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt;(scene, &lt;/span&gt;&lt;span&gt;mimeType&lt;/span&gt;&lt;span&gt;: .png) { engine &lt;/span&gt;&lt;span&gt;in&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  try&lt;/span&gt;&lt;span&gt; engine.scene.&lt;/span&gt;&lt;span&gt;getPages&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;span&gt;forEach&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    try&lt;/span&gt;&lt;span&gt; engine.block.&lt;/span&gt;&lt;span&gt;setScopeEnabled&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;$0&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;layer/visibility&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;enabled&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    try&lt;/span&gt;&lt;span&gt; engine.block.&lt;/span&gt;&lt;span&gt;setVisible&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;$0&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;visible&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; url &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; FileManager.default.temporaryDirectory.&lt;/span&gt;&lt;span&gt;appendingPathComponent&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;Export&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;conformingTo&lt;/span&gt;&lt;span&gt;: .png)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;try&lt;/span&gt;&lt;span&gt; data.&lt;/span&gt;&lt;span&gt;write&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;to&lt;/span&gt;&lt;span&gt;: url, &lt;/span&gt;&lt;span&gt;options&lt;/span&gt;&lt;span&gt;: [.atomic])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;eventHandler.&lt;/span&gt;&lt;span&gt;send&lt;/span&gt;&lt;span&gt;(.&lt;/span&gt;&lt;span&gt;shareFile&lt;/span&gt;&lt;span&gt;(url))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is the callback to rewrite when the edited photo should go somewhere else, up to our own backend, say, or straight back to the screen the user came from. By that point the encoded image is already in &lt;code&gt;data&lt;/code&gt;, so a share sheet is only one of the options.&lt;/p&gt;
&lt;h2 id=&quot;before-we-ship-it&quot;&gt;Before we ship it&lt;/h2&gt;
&lt;p&gt;Three things are still sitting on their development defaults.&lt;/p&gt;
&lt;p&gt;The first is the license. Passing &lt;code&gt;nil&lt;/code&gt; keeps the watermark, so a production build needs a real key in &lt;code&gt;EngineSettings&lt;/code&gt;. Trial keys are available through the &lt;a href=&quot;https://img.ly/docs/cesdk/ios/get-started/overview-e18f40/&quot;&gt;CE.SDK iOS guide&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The second is the &lt;code&gt;userID&lt;/code&gt;, which still reads &lt;code&gt;&amp;#x3C;your unique user id&gt;&lt;/code&gt;. That string compiles, so every user of a shipped app reports the same id. Pass a stable identifier for the signed-in user, or leave the parameter out, since it defaults to &lt;code&gt;nil&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The third is where the assets come from. Filters, typefaces, stickers, and shapes load from &lt;code&gt;https://cdn.img.ly/packages/imgly/cesdk-swift/1.82.1/assets&lt;/code&gt;, the default &lt;code&gt;baseURL&lt;/code&gt;, and that CDN is for development. Self-hosting is required for a production deployment: download the &lt;a href=&quot;https://cdn.img.ly/packages/imgly/cesdk-swift/1.82.1/imgly-assets.zip&quot;&gt;asset archive&lt;/a&gt;, put it somewhere we control, and pass our own &lt;code&gt;baseURL&lt;/code&gt; to &lt;code&gt;EngineSettings&lt;/code&gt;. &lt;a href=&quot;https://img.ly/docs/cesdk/ios/serve-assets-b0827c/&quot;&gt;Serve Assets From Your Server&lt;/a&gt; walks through the hosting side. That’s also the moment to drop the sources we never load, which shortens the editor’s startup.&lt;/p&gt;
&lt;h2 id=&quot;where-to-go-next&quot;&gt;Where to go next&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://img.ly/docs/cesdk/ios/starterkits/photo-editor-r6kq0u/&quot;&gt;Photo Editor starter kit guide&lt;/a&gt; documents the parts of the kit we skipped, and the &lt;a href=&quot;https://img.ly/docs/cesdk/ios/&quot;&gt;iOS documentation&lt;/a&gt; covers the rest of the platform. The same editor goes into &lt;a href=&quot;blog/how-to-integrate-a-photo-editor-into-your-website-4578cc6ef6f3/&quot;&gt;a website&lt;/a&gt; and into &lt;a href=&quot;blog/how-to-integrate-a-photo-editor-into-your-android-app-ee4148816e25/&quot;&gt;an Android app&lt;/a&gt;.&lt;/p&gt;</content:encoded><dc:creator>Felix</dc:creator><media:content url="https://blog.img.ly/2020/04/image-32.png" medium="image"/><category>iOS</category><category>App Development</category><category>Swift Package Manager</category><category>Tutorial</category><category>Technology</category><category>Tech</category><category>How-To</category><category>Learning</category></item></channel></rss>