<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Matheus Cardoso</title>
    <description>The latest articles on DEV Community by Matheus Cardoso (@cardoso).</description>
    <link>https://dev.to/cardoso</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F39988%2Fb70600ba-81e5-457d-a103-3527b2b8f6bc.jpg</url>
      <title>DEV Community: Matheus Cardoso</title>
      <link>https://dev.to/cardoso</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/cardoso"/>
    <language>en</language>
    <item>
      <title>iOS Passwordless Chat Application with Auth0</title>
      <dc:creator>Matheus Cardoso</dc:creator>
      <pubDate>Tue, 01 Jun 2021 15:16:31 +0000</pubDate>
      <link>https://dev.to/cardoso/ios-passwordless-chat-application-with-auth0-2lc8</link>
      <guid>https://dev.to/cardoso/ios-passwordless-chat-application-with-auth0-2lc8</guid>
      <description>&lt;p&gt;Almost every application needs an authentication strategy. The most common being the classic username and password combo. However, there's a new approach some apps are taking to avoid handling or storing user passwords: &lt;a href="https://auth0.com/passwordless"&gt;passwordless authentication&lt;/a&gt;. It generally involves sending a one-time PIN (OTP) through a user-owned channel such as their phone or email. If the user inputs the correct PIN, we give them access to the system.&lt;/p&gt;

&lt;p&gt;In this article, we'll &lt;a href="https://getstream.io/tutorials/ios-chat/"&gt;build an iOS chat application&lt;/a&gt; with &lt;a href="https://getstream.io/chat/"&gt;Stream Chat&lt;/a&gt;, for its &lt;a href="https://getstream.io/chat/sdk/ios"&gt;fully featured iOS chat components&lt;/a&gt; and &lt;a href="https://auth0.com"&gt;Auth0&lt;/a&gt;'s passwordless features for authentication.&lt;/p&gt;

&lt;p&gt;You can see the final result in the screenshot below and download the complete source code in the &lt;a href="https://github.com/GetStream/passwordless-chat-app-ios"&gt;Passwordless Chat App iOS GitHub repository&lt;/a&gt;. Let's dive in!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--j8glm1Ds--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.imgur.com/KlgppiG.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--j8glm1Ds--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.imgur.com/KlgppiG.png" alt="Image shows a passwordless login screen and a screen with chat channels" width="800" height="803"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;p&gt;To follow this tutorial, create an account with Stream, Auth0, and Ngrok. You'll also need Xcode, NodeJS, and Ngrok installed.&lt;/p&gt;

&lt;p&gt;Stream takes care of the chat features, Auth0 provides the passwordless authentication we need, and Ngrok lets us quickly expose our local NodeJS backend to the external world via HTTPS.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;a href="https://getstream.io/accounts/signup/"&gt;Stream account&lt;/a&gt; account&lt;/li&gt;
&lt;li&gt;An &lt;a href="https://auth0.com/signup"&gt;Auth0 account&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;An &lt;a href="https://dashboard.ngrok.com/signup"&gt;Ngrok account&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://nodejs.org/"&gt;Node v14&lt;/a&gt; installed&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ngrok.com/download"&gt;Ngrok installed&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Xcode 12 or later&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Auth0's free plan includes the passwordless feature, and if you're an independent developer or with a small team, you may be eligible for &lt;a href="https://getstream.io/maker-account/"&gt;Stream's free maker account&lt;/a&gt;. So, remember to sign up for it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Create iOS Project
&lt;/h2&gt;

&lt;p&gt;Since we'll need some details of the iOS project to configure the Auth0 dashboard, let's first create a UIKit project on Xcode with the UIKit App Delegate lifecycle.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Pqys0AtT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.imgur.com/uQprGzd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Pqys0AtT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.imgur.com/uQprGzd.png" alt="Image shows an iOS project created on Xcode" width="800" height="546"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure Auth0 Account
&lt;/h2&gt;

&lt;p&gt;Before we can dive into the code, let's visit our Auth0 account to enable passwordless authentication and get the credentials we need.&lt;/p&gt;

&lt;p&gt;After you've &lt;a href="https://auth0.com/signup"&gt;created your Auth0 account&lt;/a&gt; and you're in the dashboard, go to &lt;code&gt;Authentication &amp;gt; Passwordless&lt;/code&gt; and enable "Email". Also, make sure to set the Default App’s switch to “on” for passwordless authentication in the Applications tab. You can also use SMS if you have a Twilio account.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MIYgSEKX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.imgur.com/eR2n7xJ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MIYgSEKX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.imgur.com/eR2n7xJ.png" alt="Image shows the Email toggle in authentication &amp;gt; Passwordless enabled" width="800" height="568"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After you've enabled Email authentication, go to your Default App in Applications and copy your Domain and Client ID. We'll need these later in the iOS code section.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0L-rVqbi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.imgur.com/PjuciFf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0L-rVqbi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.imgur.com/PjuciFf.png" alt="Image shows Domain and Client ID in Auth0 dashboard" width="800" height="568"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After that, scroll a bit down to &lt;code&gt;Application Properties&lt;/code&gt; and change your application type to &lt;code&gt;Native&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--__VwaUvF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.imgur.com/Emhu5rB.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--__VwaUvF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.imgur.com/Emhu5rB.png" alt="Image shows Application Type native in Auth0 dashboard" width="800" height="578"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once that's done, scroll further down to &lt;code&gt;Advanced Settings &amp;gt; Device Settings&lt;/code&gt; and paste your Team ID (DEVELOPMENT_TEAM) and App ID (PRODUCT_BUNDLE_IDENTIFIER), which you can find in your Xcode .pbxproj file, which is contained within the .xcodeproj file. To reveal the .pbxproj file, right click the .xcodeproj file and select Show Package Contents.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SvPHR9iG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.imgur.com/A0AXqto.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SvPHR9iG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.imgur.com/A0AXqto.png" alt="Image shows team id and app id fields in Auth0 dashboard" width="800" height="578"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, move to the Grant Types tab, enable Passwordless OTP, and hit save.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WUEYd13p--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.imgur.com/itSurMH.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WUEYd13p--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.imgur.com/itSurMH.png" alt="Image shows grant type passwordless OTP enabled in the Auth0 dashboard" width="800" height="578"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After that, move to the Certificates tab, download your PEM certificate, name it &lt;code&gt;public.pem&lt;/code&gt;, and place it in the same folder as your backend's &lt;code&gt;index.js&lt;/code&gt;. You will use this certificate to verify the authentication request in your backend.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--k5KOuC3V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.imgur.com/U8g5iVY.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k5KOuC3V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.imgur.com/U8g5iVY.png" alt="Image shows user downloading PEM certificate in Auth0 dashboard" width="800" height="634"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Create Backend Project
&lt;/h2&gt;

&lt;p&gt;The backend consists of a single endpoint that generates a Stream JWT for a given user id. When the iOS app makes this request, it must also include an Auth0 ID Token to be verified. If the verification fails, we return 401 (Unauthorized) instead of the token. If it succeeds, we produce the Stream token, thus providing our user access to the chat feature under the given user id.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Install the dependencies with &lt;code&gt;npm install express stream-chat jsonwebtoken --save&lt;/code&gt; or &lt;code&gt;yarn add express stream-chat jsonwebtoken&lt;/code&gt;, then run your backend with &lt;code&gt;node index.js&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Ngrok
&lt;/h2&gt;

&lt;p&gt;To access this endpoint outside our local machine and serve it under HTTPS (ideal for iOS apps), we can use Ngrok. You can install Ngrok through homebrew by running the command &lt;code&gt;brew install ngrok&lt;/code&gt;, or visit the &lt;a href="https://ngrok.com/download"&gt;Ngrok website&lt;/a&gt;. You'll also need an account and the auth token set up.&lt;/p&gt;

&lt;p&gt;After you have Ngrok and your account set up, run &lt;code&gt;ngrok http 3000&lt;/code&gt;. If your backend is running on a different port than 3000, make sure to use that number instead. After you run the command, you should copy the https URL. You'll need it in the next section.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AAKuSMiM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.imgur.com/OVNWqa1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AAKuSMiM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.imgur.com/OVNWqa1.png" alt="Image shows ngrok executing and outputting URLs" width="800" height="643"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  iOS Dependencies
&lt;/h2&gt;

&lt;p&gt;Add the following dependencies to your iOS project.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/getstream/stream-chat-swift"&gt;https://github.com/getstream/stream-chat-swift&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/auth0/Lock.swift"&gt;https://github.com/auth0/Lock.swift&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can install the dependencies with Xcode's built-in Swift Package Manager integration or CocoaPods.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6Rmi1o8R--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.imgur.com/jWYvYAE.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6Rmi1o8R--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.imgur.com/jWYvYAE.png" alt="Image shows an iOS project with the Stream Chat Swift and Auth0 Lock dependencies" width="800" height="456"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  iOS Code
&lt;/h2&gt;

&lt;p&gt;First, we need code to ask our backend for the JWT. You can write a stand-alone function that does it like below. Remember to replace the Ngrok URL. You can paste the function anywhere you want. For example, you can create a fetchStreamJWT.swift file and paste it there.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;After that, we also need a function that creates our Chat's UI stack. After reading &lt;a href="https://getstream.io/tutorials/ios-chat/"&gt;Stream Chat's iOS Tutorial&lt;/a&gt;, we can quickly write a stand-alone function that sets up our UI. As with the last function, you can create a makeChat.swift file and paste it there.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;In the ViewController.swift file, we'll use Auth0's Lock.swift SDK to show the authentication UI. Once the user inputs the OTP, the &lt;code&gt;onAuth&lt;/code&gt; callback is triggered, giving us the Auth0 ID token. We then call &lt;code&gt;fetchStreamJWT&lt;/code&gt; to hit our endpoint and &lt;code&gt;makeChat&lt;/code&gt; to display our chat UI.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  Testing Your App
&lt;/h2&gt;

&lt;p&gt;If everything is right and your backend is running, you should be able to run your project in a device or simulator. Type in your email, and you'll receive a code. After typing the code correctly and pressing submit, it will take you to the chat screen.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--j8glm1Ds--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.imgur.com/KlgppiG.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--j8glm1Ds--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.imgur.com/KlgppiG.png" alt="Image shows a passwordless login screen and a screen with chat channels" width="800" height="803"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Next Steps with the Passwordless Chat App
&lt;/h2&gt;

&lt;p&gt;Congratulations! You've built the basis of a functioning passwordless chat app with &lt;a href="https://getstream.io/chat/"&gt;Stream Chat&lt;/a&gt; and &lt;a href="https://auth0.com"&gt;Auth0&lt;/a&gt;. I encourage you to browse through &lt;a href="https://getstream.io/chat/docs/ios-swift/"&gt;Stream Chat's docs&lt;/a&gt;, &lt;a href="https://auth0.com/docs/libraries/auth0-swift/auth0-swift-passwordless"&gt;Auth0's iOS passwordless docs&lt;/a&gt;, and experiment with the project you just built. Good luck on your app development!&lt;/p&gt;

</description>
      <category>ios</category>
      <category>swift</category>
      <category>programming</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Generate JWTs with Swift on AWS Lambda</title>
      <dc:creator>Matheus Cardoso</dc:creator>
      <pubDate>Fri, 12 Mar 2021 13:07:48 +0000</pubDate>
      <link>https://dev.to/cardoso/generate-jwts-with-swift-on-aws-lambda-1mb7</link>
      <guid>https://dev.to/cardoso/generate-jwts-with-swift-on-aws-lambda-1mb7</guid>
      <description>&lt;p&gt;Authorization is one of the essential parts of any iOS application. Once a user is logged in, it's your authorization scheme that will make sure users can't interact with your app in ways they're not allowed to. Without a robust authorization scheme, hackers could easily access sensitive user data and engage in other damaging activities such as scamming. &lt;/p&gt;

&lt;p&gt;Thankfully, the widespread use and standardization of &lt;a href="https://jwt.io/" rel="noopener noreferrer"&gt;JWT (JSON Web Tokens)&lt;/a&gt; have made robust and cryptographically secure authorization more straightforward to achieve.&lt;/p&gt;

&lt;p&gt;In this article, we'll use &lt;a href="https://getstream.io/chat/" rel="noopener noreferrer"&gt;Stream Chat&lt;/a&gt; as an example service to authorize our users for using &lt;a href="https://github.com/getstream/swift-lambda/" rel="noopener noreferrer"&gt;Swift Lambda&lt;/a&gt; to generate JWTs. You can then use the JWT for interacting with the Stream Chat service via the &lt;a href="https://getstream.io/chat/docs_rest/" rel="noopener noreferrer"&gt;REST API&lt;/a&gt; or by configuring the &lt;a href="https://getstream.io/chat/sdk/ios/" rel="noopener noreferrer"&gt;iOS Chat SDK&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is JSON Web Token?
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA or ECDSA.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://jwt.io/introduction" rel="noopener noreferrer"&gt;Introduction to JSON Web Tokens&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  How does it work?
&lt;/h2&gt;

&lt;p&gt;After authenticating with a login and password or another method, the user receives a JWT. After authentication, the user will attach this JWT to every request as a way of proving their identity and permission to access a particular resource. This JWT was signed by your server during authentication using a secret key and is verified in subsequent requests.&lt;/p&gt;

&lt;h2&gt;
  
  
  Set Up Swift Lambda
&lt;/h2&gt;

&lt;p&gt;Since JWTs should be generated and verified server-side, we can &lt;a href="https://getstream.io/blog/swift-lambda-aws-serverless/" rel="noopener noreferrer"&gt;set up an AWS Lambda written in Swift&lt;/a&gt; to do that job. You can choose an alternative method and language, but the next steps will be different. By the end, we'll have an HTTP endpoint that outputs a JWT for a specific user id to access &lt;a href="https://getstream.io/chat/" rel="noopener noreferrer"&gt;Stream's chat service&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install Kitura's Swift-JWT
&lt;/h3&gt;

&lt;p&gt;To generate a JWT, we'll use &lt;a href="https://github.com/Kitura/Swift-JWT" rel="noopener noreferrer"&gt;Kitura's Swift-JWT&lt;/a&gt; package, which takes care of the heavy lifting of building a JWT.&lt;/p&gt;

&lt;p&gt;To install it, open your Swift Lambda's &lt;code&gt;Package.swift&lt;/code&gt; in its root folder and add &lt;code&gt;.package(name: "SwiftJWT", url: "https://github.com/Kitura/Swift-JWT.git", from: "3.6.2")&lt;/code&gt; to the package's dependency list. Also, add &lt;code&gt;"SwiftJWT"&lt;/code&gt; to the Lambda target's dependency list. By the end, your Package.swift will look similar to the one below.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  Install OpenSSL
&lt;/h2&gt;

&lt;p&gt;Swift-JWT depends on the OpenSSL library to perform cryptographic operations. To install it, add &lt;code&gt;RUN yum -y install openssl-devel&lt;/code&gt; to your Swift Lambda's Dockerfile which can be found in its root folder. The Dockerfile should look similar to the one below.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  Configure Endpoint
&lt;/h2&gt;

&lt;p&gt;Finally, we'll need our endpoint to accept &lt;code&gt;POST&lt;/code&gt; requests, since we'll send credentials in the request body. To do that, change the Swift Lambda's &lt;code&gt;serverless.yml&lt;/code&gt; line from &lt;code&gt;method: get&lt;/code&gt; to &lt;code&gt;method: post&lt;/code&gt;. It will look similar to the snippet below.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  Parse Request
&lt;/h2&gt;

&lt;p&gt;After you're done configuring your Swift Lambda, we can start writing code in &lt;code&gt;Sources/Lambda/main.swift&lt;/code&gt;. The code we need will parse a POST request and extract the &lt;code&gt;user_id&lt;/code&gt; field from its JSON body. After that, it will generate a JWT for that user id and return it.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;We'll implement the &lt;code&gt;generateJWT(for userId: String)&lt;/code&gt; function in the next steps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sign Up to Stream
&lt;/h2&gt;

&lt;p&gt;Before we can generate a JWT, we need a secret to sign it. You can get one by &lt;a href="https://getstream.io/chat/trial/" rel="noopener noreferrer"&gt;signing up to Stream&lt;/a&gt; or by accessing the &lt;a href="https://getstream.io/dashboard/" rel="noopener noreferrer"&gt;dashboard&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FKol4QHj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FKol4QHj.png" alt="Image shows secret in Stream dashboard"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Generate JWT
&lt;/h2&gt;

&lt;p&gt;To generate a JWT, we'll use SwiftJWT. First, we need to declare a struct conforming to the &lt;code&gt;Claims&lt;/code&gt; protocol with a &lt;code&gt;user_id&lt;/code&gt; property of type &lt;code&gt;String&lt;/code&gt;. That's the only claim required by Stream. After that, we create a JWT object with the user_id claim and sign it using your Stream secret.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Note: Before you generate a JWT, it's essential to verify the request with some form of authentication such as a password and return &lt;code&gt;401 Unauthorized&lt;/code&gt; if it's wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploy
&lt;/h2&gt;

&lt;p&gt;The main advantage of using &lt;a href="https://github.com/GetStream/swift-lambda" rel="noopener noreferrer"&gt;Swift Lambda&lt;/a&gt; is that it's possible to iterate fast with it. After writing the JWT code, just run the &lt;code&gt;./Scripts/deploy.sh&lt;/code&gt; script again and wait a few seconds.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FPMOl2nU.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FPMOl2nU.png" alt="This image shows the deploy script finishing successfully"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Test the Endpoint
&lt;/h2&gt;

&lt;p&gt;To test the endpoint and get a JWT, you can use the following curl command in your terminal. Don't forget to replace the URL with the one you got in the deploy step and change the user id if you want to.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;After running that command, you should get a valid JWT. If it has a &lt;code&gt;%&lt;/code&gt; at the end, ignore it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FjQdgfer.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FjQdgfer.png" alt="Image shows curl command running and a JWT output"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Congratulations! You've generated a valid JWT for interacting with the Stream Chat service via the &lt;a href="https://getstream.io/chat/docs_rest" rel="noopener noreferrer"&gt;REST API&lt;/a&gt; or by configuring the &lt;a href="https://getstream.io/chat/sdk/ios." rel="noopener noreferrer"&gt;iOS Chat SDK&lt;/a&gt;. This logic can be adapted to work with other JWT-based services such as &lt;a href="https://auth0.com/" rel="noopener noreferrer"&gt;Auth0&lt;/a&gt; and &lt;a href="https://dolby.io/" rel="noopener noreferrer"&gt;Dolby.io&lt;/a&gt;. To find out what else you can build with Swift on AWS Lambda, check out the &lt;a href="https://github.com/getstream/swift-lambda/" rel="noopener noreferrer"&gt;Swift Lambda repository on GitHub&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ios</category>
      <category>swift</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Swift WebSockets: Starscream or URLSession in 2021?</title>
      <dc:creator>Matheus Cardoso</dc:creator>
      <pubDate>Tue, 02 Mar 2021 17:37:43 +0000</pubDate>
      <link>https://dev.to/cardoso/swift-websockets-starscream-or-urlsession-in-2021-fck</link>
      <guid>https://dev.to/cardoso/swift-websockets-starscream-or-urlsession-in-2021-fck</guid>
      <description>&lt;p&gt;Building applications such as online games and &lt;a href="https://getstream.io/chat/" rel="noopener noreferrer"&gt;real-time chat&lt;/a&gt; has never been easier since the standardisation of the WebSocket protocol in 2011. Before that, most app experiences were plagued with manual refreshes in order to access the latest data available (remember F5?). Since then, most apps use WebSockets in some form to update their user interface with new data as soon as it is generated.&lt;/p&gt;

&lt;p&gt;For Swift programmers targeting iOS, macOS, and other Apple platforms in 2021, there are two main libraries that can be used to connect to a WebSocket server: &lt;a href="https://github.com/daltoniam/Starscream" rel="noopener noreferrer"&gt;Starscream&lt;/a&gt; and &lt;a href="https://developer.apple.com/documentation/foundation/urlsession" rel="noopener noreferrer"&gt;URLSession&lt;/a&gt;. While both are capable libraries, they also have advantages and disadvantages which are important to consider before choosing one over the other.&lt;/p&gt;

&lt;p&gt;In this article, we'll go over several positive and negative characteristics of Starscream and URLSession to help you decide which fits best with your requirements. Let's dig in!&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the WebSocket Protocol
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;The WebSocket Protocol enables two-way communication between a client running untrusted code in a controlled environment to a remote host that has opted-in to communications from that code. The security model used for this is the origin-based security model commonly used by web browsers. The protocol consists of an opening handshake followed by basic message framing, layered over TCP. The goal of this technology is to provide a mechanism for browser-based applications that need two-way communication with servers that does not rely on opening multiple HTTP connections (e.g., using XMLHttpRequest or s and long polling).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://tools.ietf.org/html/rfc6455" rel="noopener noreferrer"&gt;RFC 6455 - The WebSocket Protocol&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Starscream
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fdaltoniam%2Fstarscream%2Fassets%2Fstarscream.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fdaltoniam%2Fstarscream%2Fassets%2Fstarscream.jpg" alt="Image shows starscream github repo's banner image"&gt;&lt;/a&gt;&lt;br&gt;
Image from &lt;a href="https://github.com/daltoniam/Starscream" rel="noopener noreferrer"&gt;https://github.com/daltoniam/Starscream&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Starscream is a conforming WebSocket (RFC 6455) library written in Swift targeting the iOS and macOS systems. Years before Apple's URLSession even supported WebSockets, Starscream was the Swift library of choice. For reasons we'll go over shortly, it is the library we use at &lt;a href="https://getstream.io/" rel="noopener noreferrer"&gt;Stream&lt;/a&gt; for building our &lt;a href="https://github.com/getstream/stream-chat-swift" rel="noopener noreferrer"&gt;iOS Chat SDK&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pros
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Legacy support
&lt;/h4&gt;

&lt;p&gt;Starscream will compile for iOS 8+ (7+ with some tweaks) and macOS 10.10+. If supporting devices with old operating systems is a requirement, you have almost no choice but to go with this library. This is the one of the main reasons we chose to go with Starscream for the &lt;a href="https://getstream.io/tutorials/ios-chat/" rel="noopener noreferrer"&gt;Stream Chat iOS SDK&lt;/a&gt; which supports iOS 11 onwards.&lt;/p&gt;

&lt;h4&gt;
  
  
  Battle tested
&lt;/h4&gt;

&lt;p&gt;Starscream has been around for a long time. It's been tested by thousands of apps and improved upon for years. It presents a reliability that may be currently unmatched among WebSocket libraries. This is another important point in our decision to stick with Starscream and it will be obvious (spoiler alert) when we talk about URLSession's reliability issues for WebSockets.&lt;/p&gt;

&lt;h4&gt;
  
  
  Open-Source
&lt;/h4&gt;

&lt;p&gt;Starscream is fully open-source up to its usage of CFNetwork calls, so it's possible to make changes if you need. It's also possible to use URLSession underneath for supported systems, but that's not enabled by default.&lt;/p&gt;

&lt;p&gt;PS: Technically, &lt;a href="https://github.com/apple/swift-corelibs-foundation" rel="noopener noreferrer"&gt;CFNetwork and URLSession are open-source&lt;/a&gt;, but you're not meant to compile your own version of them for production use in Apple platforms so it doesn't count, right?&lt;/p&gt;

&lt;h3&gt;
  
  
  Cons
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Binary Size
&lt;/h4&gt;

&lt;p&gt;Since Starscream is not shipped with Apple's operating systems, including it in your project will cause an increase in your binary size of about 500kb which is not terrible for regular apps, but could be a real issue for size-restrictive targets such as the new App Clips.&lt;/p&gt;

&lt;h4&gt;
  
  
  Maintenance
&lt;/h4&gt;

&lt;p&gt;Since the release of URLSession support for WebSockets in 2019, the Starscream repository has seen a steady decrease in activity with many unanswered issues and pull requests, with the last commit merged in August 2020. This is a sign that if you run into bugs or need a new feature it could be a dead end unless you handle it yourself.&lt;/p&gt;




&lt;h2&gt;
  
  
  URLSession
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi1.wp.com%2Fpixahive.com%2Fwp-content%2Fuploads%2F2020%2F11%2FApple-logo-for-iphone-phone-195578-pixahive.jpg%3Ffit%3D1560%252C873%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi1.wp.com%2Fpixahive.com%2Fwp-content%2Fuploads%2F2020%2F11%2FApple-logo-for-iphone-phone-195578-pixahive.jpg%3Ffit%3D1560%252C873%26ssl%3D1" alt="Image shows apple logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;URLSession is Apple's own high-level networking library for HTTP(S) requests. To be more precise, URLSession is really a class that's part of the Foundation library. It coordinates a group of related, network data-transfer tasks, and, as of iOS 13 and macOS 10.15, it supports WebSockets as one of those tasks (URLSessionWebSocketTask).&lt;/p&gt;

&lt;h3&gt;
  
  
  Pros
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Binary size
&lt;/h4&gt;

&lt;p&gt;Using URLSession in your app will not cause any noticeable increase in your final binary size since it's included in the system's Foundation library. When you need to optimize for size, such as when building an App Clip, then URLSession is your library of choice!&lt;/p&gt;

&lt;h4&gt;
  
  
  Maintained By Apple
&lt;/h4&gt;

&lt;p&gt;URLSession is maintained by Apple and should receive regular updates for the foreseeable future, though they can only be taken advantage by installing new operating system patches. You can also ask for support directly from Apple if you are enrolled in their paid &lt;a href="https://developer.apple.com/programs/whats-included/" rel="noopener noreferrer"&gt;developer program&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cons
&lt;/h3&gt;

&lt;h4&gt;
  
  
  No Legacy Support
&lt;/h4&gt;

&lt;p&gt;URLSession only received WebSockets support in 2019 when iOS 13 and macOS 10.15 were released. As such, using it for Web Sockets will restrict your app to those versions and up.&lt;/p&gt;

&lt;h4&gt;
  
  
  Closed-Source
&lt;/h4&gt;

&lt;p&gt;URLSession is closed-source, so it's not possible to make any changes to the underlying implementation in case you need them. Again, using a looser definition of close-source, since technically you can get the source code on GitHub, but it's not viable to compile your own version of it.&lt;/p&gt;

&lt;h4&gt;
  
  
  Unreliability &amp;amp; Crashes
&lt;/h4&gt;

&lt;p&gt;It's expected that a function developed not long ago still presents rough edges. If you search the web for "URLSessionWebSocketTask crash" or "URLSessionWebSocketTask bug", you'll find many instances on &lt;a href="https://stackoverflow.com/questions/60110667/urlsessionwebsockettask-fatal-error-only-one-of-message-or-error-should-be-nil" rel="noopener noreferrer"&gt;StackOverflow&lt;/a&gt; and even &lt;a href="https://developer.apple.com/forums/thread/117827" rel="noopener noreferrer"&gt;Apple's forums&lt;/a&gt; of developers reporting crashes and other issues.&lt;/p&gt;




&lt;h2&gt;
  
  
  Which You Should Choose
&lt;/h2&gt;

&lt;p&gt;Given URLSession has implemented support for WebSockets relatively recently, it's not currently as reliable as Starscream which existed for years prior. Many projects that migrated from Starscream to URLSession reported mysterious bugs and crashes. This alone gives Starscream the top spot among Swift WebSocket libraries. But keep on reading, there are other things to consider.&lt;/p&gt;

&lt;p&gt;When Apple fixes the reliability issues, the most defining point in choosing these libraries is going to be about legacy support. If your app needs to support system versions lower than iOS 13 / macOS 10.15, your best bet will be to use Starscream. If your app only supports those versions and up, it will be better to take advantage of the native URLSession framework and Apple's extended support of it.&lt;/p&gt;

&lt;p&gt;For App Clips, URLSession is currently preferred due to Starscream's 500kb binary size impact. With just a little bit of luck, you might escape its reliability issues.&lt;/p&gt;

</description>
      <category>ios</category>
      <category>beginners</category>
      <category>swift</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Singleton vs Dependency Injection in Swift</title>
      <dc:creator>Matheus Cardoso</dc:creator>
      <pubDate>Tue, 16 Feb 2021 14:03:04 +0000</pubDate>
      <link>https://dev.to/cardoso/singleton-vs-dependency-injection-in-swift-3k1f</link>
      <guid>https://dev.to/cardoso/singleton-vs-dependency-injection-in-swift-3k1f</guid>
      <description>&lt;p&gt;When coding iOS apps, we often create classes that manage a particular aspect of the application. For example, it's common to develop "manager" classes that encapsulate methods for interacting with a specific application aspect. These aspects commonly include the REST API, WebSockets, database, caching, notifications, &lt;a href="https://getstream.io/chat/" rel="noopener noreferrer"&gt;chat&lt;/a&gt;, etc. That is what's called the &lt;a href="https://refactoring.guru/design-patterns/facade" rel="noopener noreferrer"&gt;Facade pattern&lt;/a&gt;, and it's a prevalent way to organize code.&lt;/p&gt;

&lt;p&gt;During the creation of a "manager" class, one of the first thoughts is: "How do I access these methods from somewhere else in my app's code, such as inside a view controller?". There are two common ways to go about this: the Singleton and Dependency Injection patterns.&lt;/p&gt;

&lt;p&gt;This article will compare the Singleton and Dependency Injection patterns to help you decide which one is best for your use case. For context, we'll use &lt;a href="https://getstream.io/tutorials/ios-chat/" rel="noopener noreferrer"&gt;Stream Chat's iOS SDK&lt;/a&gt;, which supports both patterns.&lt;/p&gt;

&lt;h2&gt;
  
  
  Singleton
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2F7nb4VMY.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2F7nb4VMY.png" alt="Image shows the representation of a singleton"&gt;&lt;/a&gt;&lt;br&gt;
Image from &lt;a href="https://refactoring.guru/design-patterns/singleton" rel="noopener noreferrer"&gt;https://refactoring.guru/design-patterns/singleton&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Singleton pattern is known for its simplicity. It consists of a Facade class with a public static instance, often called &lt;code&gt;shared&lt;/code&gt;, accessible throughout the app's code via &lt;code&gt;MyFacade.shared&lt;/code&gt;. Generally, the Facade's class initializer is made private, so the shared instance is the only one in the app.&lt;/p&gt;

&lt;p&gt;Check out the snippet below to create a shared instance for &lt;a href="https://getstream.io/chat/" rel="noopener noreferrer"&gt;Stream Chat&lt;/a&gt;'s &lt;code&gt;ChatClient&lt;/code&gt; class by extending it with the &lt;code&gt;shared&lt;/code&gt; static property.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h3&gt;
  
  
  Pros
&lt;/h3&gt;

&lt;p&gt;The main advantage of the singleton pattern is its ease of access. Wherever you need the shared instance, you can access it without modifying your code further.&lt;/p&gt;

&lt;p&gt;It's also possible to enforce a single instance if you make the Facade class's initializer private. That is a simple way to avoid common conflicts such as concurrent writes to a database.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cons
&lt;/h3&gt;

&lt;p&gt;The disadvantages of the singleton pattern become apparent the more complex your app gets. The more places in your app access the shared instance, the more unpredictable your app's behavior becomes and the harder it is to keep all your code in sync with the singleton's global state. Though it can be handy for more uncomplicated use cases, it's often considered an anti-pattern by those who want to be more careful with their code and increase predictability.&lt;/p&gt;

&lt;p&gt;It's also possible that limiting the Facade class to a single instance is not what you'll want as your app scales up, and it can be tough to undo that choice. &lt;/p&gt;

&lt;p&gt;It's also harder to write unit tests without the possibility of instantiating a mock instance of your class. The last point is not valid for &lt;a href="https://github.com/getstream/stream-chat-swift/" rel="noopener noreferrer"&gt;Stream Chat Swift SDK&lt;/a&gt;'s &lt;code&gt;ChatClient&lt;/code&gt;, since its initializer is public to support the Dependency Injection pattern, which we'll discuss next.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dependency Injection
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FBkDFSed.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FBkDFSed.png" alt="Image shows the representation of dependency injection"&gt;&lt;/a&gt;&lt;br&gt;
Image from &lt;a href="https://stackify.com/dependency-injection/" rel="noopener noreferrer"&gt;https://stackify.com/dependency-injection/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Dependency Injection can be a great alternative to the Singleton pattern for medium to high complexity apps as it scales with your app with less risk of adding unpredictability. Instead of providing a shared instance that can be accessed without restriction throughout the app, each component or class that needs access to an instance must hold its reference via a parameter or property. This property can be assigned during instantiation or after.&lt;/p&gt;

&lt;p&gt;Check out the snippet below to instantiate a &lt;code&gt;ChatClient&lt;/code&gt; and a &lt;code&gt;ViewController&lt;/code&gt; with the former going into its initializer. Alternatively, we can assign the ViewController's &lt;code&gt;chatClient&lt;/code&gt; property after initialization. It would be best if you prefer using the initializer approach to avoid making the property public.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  Pros
&lt;/h2&gt;

&lt;p&gt;There are multiple advantages to the Dependency Injection pattern. Since instantiation is not limited, it's possible to create mock instances to use in unit testing. Additionally, you're not locking yourself out of using multiple instances at the same time in case it's necessary now or in the future.&lt;/p&gt;

&lt;p&gt;An injected dependency behavior is also more predictable since its accesses are restricted to pieces of code that explicitly hold an instance to it. Hence, you get to think twice about where to access it.&lt;/p&gt;

&lt;p&gt;Dependency Injection doesn't add a global state to your code, so it becomes more reusable. If your code component &lt;/p&gt;

&lt;h2&gt;
  
  
  Cons
&lt;/h2&gt;

&lt;p&gt;The disadvantages of Dependency Injection are debatable, depending on your use case. For instance, to access the object, you need to add a property or parameter to hold its reference. That can break API in existing projects, if it's something important, or be an additional step in the development process.&lt;/p&gt;

&lt;p&gt;With Dependency Injection, it's not possible to enforce a single instance in compile-time. If multiple instances of an object can cause conflicts in runtime, it's necessary to handle those potential issues.&lt;/p&gt;

&lt;p&gt;Though not necessarily complicated, some Dependency Injection implementations do get quite robust and can be hard to grasp if you're new to the project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which You Should Choose
&lt;/h2&gt;

&lt;p&gt;It depends. Dependency Injection is widely considered the cleaner option, but it can get tricky. Singleton is regarded as an anti-pattern by Clean Code advocates, but it's easy, and it works. Still, developers use both patterns to great success. You should choose the one that fits your current project best while avoiding its common pitfalls.&lt;/p&gt;

&lt;p&gt;Finally, as important as choosing the right pattern, don't let your Manager/Facade class become a "god class" with too many responsibilities. Try to make it as single-purposed as possible by interacting with a single aspect of your app.&lt;/p&gt;

</description>
      <category>ios</category>
      <category>swift</category>
      <category>beginners</category>
      <category>programming</category>
    </item>
    <item>
      <title>Migrate Your iOS Project From Carthage To Swift Package Manager</title>
      <dc:creator>Matheus Cardoso</dc:creator>
      <pubDate>Wed, 02 Dec 2020 16:25:24 +0000</pubDate>
      <link>https://dev.to/cardoso/migrate-your-ios-project-from-carthage-to-swift-package-manager-3p70</link>
      <guid>https://dev.to/cardoso/migrate-your-ios-project-from-carthage-to-swift-package-manager-3p70</guid>
      <description>&lt;p&gt;Since Swift 5 and Xcode 11 were released, SPM became a viable dependency manager for many iOS projects. It's also been heavily improved upon in Xcode 12 with the &lt;a href="https://pspdfkit.com/blog/2020/binary-frameworks-as-swift-packages/"&gt;support of binary frameworks&lt;/a&gt; and resource files such as storyboards, nibs, localization folders, asset catalogs, and core data models. It's now possible to use it in most if not all iOS projects. And most actively maintained dependencies such as &lt;a href="https://getstream.io/chat/"&gt;Stream Chat&lt;/a&gt; support it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---xFCgKge--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.imgur.com/YnC6ymm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---xFCgKge--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.imgur.com/YnC6ymm.png" alt="Image shows Carthage logo with an arrow pointing to a Swift Package Manager logo" width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A &lt;a href="https://twitter.com/cardosodev/status/1316016310044639248"&gt;Twitter poll&lt;/a&gt; showed that, while CocoaPods is number one at 46.5%, 11.4% of iOS developers still use Carthage as their preferred dependency manager. Swift Package Manager, though released most recently, is just behind with 42.1%.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cmB-jSb_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.imgur.com/qBrdtBD.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cmB-jSb_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.imgur.com/qBrdtBD.jpg" alt="Twitter poll shows 11.4% of Carthage usage, 46.5% of CocoaPods, and 42.1% of Swift Package Manager" width="800" height="456"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's clear that SPM, with all its recent updates and deep integration with the official iOS toolchain, will soon take over the other options. In this article, I'll present a process that you can use to fully migrate your projects from Carthage to Swift Package Manager. If you're also interested in migrating from CocoaPods, here's a CocoaPods version of this article: &lt;a href="https://getstream.io/blog/migrate-cocoapods-to-spm/"&gt;Migrate Your iOS Project From CocoaPods To Swift Package Manager&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Remove Carthage
&lt;/h2&gt;

&lt;p&gt;Unlike CocoaPods, removing Carthage is an entirely manual process. You'll delete files and remove settings in your Xcode projects that reference Carthage. Most of these, you or someone on your team created manually, so what you must change can vary slightly.&lt;/p&gt;

&lt;p&gt;Before you remove Carthage, it's important to note each dependency in your project and their versions. In my case, I was only using &lt;a href="https://getstream.io/chat/"&gt;Stream Chat&lt;/a&gt; in version 2.5.0.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Now, let's remove Carthage from your project. After you took note of the contents of your Cartfile, you can remove it alongside Cartfile.resolved and the Carthage folder using the &lt;code&gt;rm -rf&lt;/code&gt; command. In my case, I also had an Xcode 12 workaround script called &lt;code&gt;carthage-build.sh&lt;/code&gt;  that I won't be needing anymore.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--128x0bw5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.imgur.com/eexGr5C.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--128x0bw5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.imgur.com/eexGr5C.png" alt="Screen shows the terminal with Carthage related files being deleted using the rm command" width="800" height="539"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Those commands removed all the Carthage-related folders and files but didn't remove the Carthage-related settings in your &lt;code&gt;.xcodeproj&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now, let's open the Xcode project and remove all frameworks in "Frameworks, Libraries, and Embedded Content" in your targets.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ohE2ETqV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.imgur.com/lppyRDS.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ohE2ETqV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.imgur.com/lppyRDS.png" alt="Screenshot shows Xcode with frameworks selected and an arrow to a minus sign" width="800" height="576"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Your &lt;code&gt;.xcodeproj&lt;/code&gt; likely contains an additional Build Phase for Carthage to copy the frameworks. You should remove it as well.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zpGEEjQ8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.imgur.com/BCLyR9G.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zpGEEjQ8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.imgur.com/BCLyR9G.png" alt="Screenshot shows Xcode with the Build Phases tab selected and an arrow pointing to an x where the Carthage build phase is" width="800" height="581"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After you're done with these steps, you likely removed all Carthage references from your project. There could be more since the usage of Carthage can vary per project. Thank you, Carthage; you've been a good friend. 😢&lt;/p&gt;

&lt;h2&gt;
  
  
  Add SPM
&lt;/h2&gt;

&lt;p&gt;After you've mourned the loss of Carthage, let's replace it with Swift Package Manager. Hopefully, you've taken notes of all the dependencies you had before. &lt;/p&gt;

&lt;p&gt;Open your &lt;code&gt;.xcodeproj&lt;/code&gt;, choose the option "Add Package Dependency" in File &amp;gt; Swift Packages, and paste the URL of your dependency's git repository. For example: "&lt;a href="https://github.com/getstream/stream-chat-swift"&gt;https://github.com/getstream/stream-chat-swift&lt;/a&gt;".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7MANLtun--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.imgur.com/devTOtz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7MANLtun--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.imgur.com/devTOtz.png" alt="Screenshot shows Xcode with the Add Package Dependency dialog opened and Stream Chat iOS SDK GitHub URL in the input field" width="800" height="549"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After pressing next, Xcode will look for the repository and automatically select the latest version tagged. If this version is compatible with the one you were using, you can press next. Otherwise, type the version you were using. After that, Xcode will download the dependency.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--eSKhizHJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.imgur.com/isVLxfL.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eSKhizHJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.imgur.com/isVLxfL.png" alt="Screenshot shows an Xcode screen selecting a dependency version and an Xcode screen downloading that dependency" width="800" height="278"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A repository may contain multiple targets. If that's the case, you should select only the ones you use.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7p88wG0a--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.imgur.com/ySfnql7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7p88wG0a--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.imgur.com/ySfnql7.png" alt="Screenshot shows an Xcode screen with dependency targets to be selected" width="800" height="549"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After you press finish, it's done! Though, you must repeat this process for each dependency you had.&lt;/p&gt;

&lt;p&gt;It's possible that a dependency doesn't provide a &lt;code&gt;Package.swift&lt;/code&gt;. In that case, it can't be used with Swift Package Manager. However, you can clone the repository and add &lt;code&gt;Package.swift&lt;/code&gt; yourself or request the maintainers to do so. For example, see the &lt;a href="https://github.com/GetStream/stream-chat-swift/commit/e406e5c406a92af42af308ee828eb582bd15ec6d#diff-f913940c58e8744a2af1c68b909bb6383e49007e6c5a12fb03104a9006ae677e"&gt;commit adding SPM support to the Stream Chat iOS SDK&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I hope you were successful in transitioning your project to the future. It's only getting better from now on. If you need any help converting your project from Carthage to Swift Package Manager, feel free to reach out to me on Twitter: &lt;a href="https://twitter.com/cardosodev"&gt;@cardosodev&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ios</category>
      <category>beginners</category>
      <category>tutorial</category>
      <category>swift</category>
    </item>
    <item>
      <title>Migrate Your iOS Project From CocoaPods To Swift Package Manager</title>
      <dc:creator>Matheus Cardoso</dc:creator>
      <pubDate>Wed, 18 Nov 2020 17:41:38 +0000</pubDate>
      <link>https://dev.to/cardoso/migrate-your-ios-project-from-cocoapods-to-swift-package-manager-4hc2</link>
      <guid>https://dev.to/cardoso/migrate-your-ios-project-from-cocoapods-to-swift-package-manager-4hc2</guid>
      <description>&lt;p&gt;As of Swift 5 and Xcode 11, &lt;a href="https://swift.org/package-manager/" rel="noopener noreferrer"&gt;Swift Package Manager&lt;/a&gt; supports the iOS, macOS, and tvOS build system. This support has also been greatly improved in Xcode 12 with the addition of non-source files, including asset catalogs, storyboards and nibs, core data models, and localization folders. It also supports &lt;a href="https://pspdfkit.com/blog/2020/binary-frameworks-as-swift-packages/" rel="noopener noreferrer"&gt;binary frameworks&lt;/a&gt;. It's clear that it's now viable for most iOS projects, and &lt;a href="https://getstream.io/blog/choose-ios-dependencies-wisely/" rel="noopener noreferrer"&gt;many dependencies&lt;/a&gt; such as &lt;a href="https://getstream.io/chat/" rel="noopener noreferrer"&gt;Stream Chat&lt;/a&gt; have implemented support for it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FKqSP9y3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FKqSP9y3.png" alt="Image shows CocoaPods logo with an arrow pointing to a Swift Package Manager logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A quick &lt;a href="https://twitter.com/cardosodev/status/1316016310044639248" rel="noopener noreferrer"&gt;Twitter poll&lt;/a&gt; showed that 46.5% of iOS developers still use CocoaPods as their primary dependency manager. Swift Package Manager follows just behind with 42.1%.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FqBrdtBD.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FqBrdtBD.jpg" alt="Twitter poll shows 46.5% of CocoaPods usage, 42.1% of Swift Package Manager, and 11.4% of Carthage"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's clear that SPM, with its recent improvements and deep integration with the official iOS toolchain, will soon take over the other options. In this article, I'll present a process that you can follow to migrate your projects to Swift Package Manager fully.&lt;/p&gt;

&lt;h2&gt;
  
  
  Remove CocoaPods
&lt;/h2&gt;

&lt;p&gt;To remove CocoaPods, you'll need the CocoaPods plugins &lt;code&gt;cocoapods-deintegrate&lt;/code&gt; and &lt;code&gt;cocoapods-clean&lt;/code&gt;. To install them, run &lt;code&gt;sudo gem install cocoapods-deintegrate cocoapods-clean&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Before you remove CocoaPods, it's important to note each dependency in your project and their versions. In my case, I was only using &lt;a href="https://getstream.io/chat/" rel="noopener noreferrer"&gt;Stream Chat&lt;/a&gt; in version 2.4.2.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Now, let's remove CocoaPods from your project. You should run the command &lt;code&gt;pod deintegrate&lt;/code&gt; in the same folder the Podfile is in.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FHg04n1M.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FHg04n1M.png" alt="Screen shows terminal with the pod deintegrate command executed and some lines of output"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That command removes the &lt;code&gt;Pods&lt;/code&gt; folder and removes the settings CocoaPods inserted in your &lt;code&gt;.xcodeproj&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now, run &lt;code&gt;pod clean&lt;/code&gt;. That command will remove some leftover files like &lt;code&gt;Podfile.lock&lt;/code&gt; and the &lt;code&gt;.xcworkspace&lt;/code&gt; originally generated by CocoaPods.&lt;/p&gt;

&lt;p&gt;It's possible that your &lt;code&gt;.xcodeproj&lt;/code&gt; still contains a reference to the &lt;code&gt;Pods&lt;/code&gt; folder. You can remove it by right-clicking the folder and selecting 'delete'. It will be gone instantly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2F11Ssc1c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2F11Ssc1c.png" alt="Screenshot shows Xcode with the Pods folder selected"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After you're done with these commands, you can put the last nail in CocoaPods's coffin with &lt;code&gt;rm Podfile&lt;/code&gt;. Thank you, CocoaPods, you've been very useful. 😢&lt;/p&gt;

&lt;h2&gt;
  
  
  Add Swift Package Manager
&lt;/h2&gt;

&lt;p&gt;After you've mourned the loss of CocoaPods, let's replace it with SPM. Hopefully, you've taken notes of all the dependencies you had. &lt;/p&gt;

&lt;p&gt;Open your &lt;code&gt;.xcodeproj&lt;/code&gt;, select the option "Add Package Dependency" in File &amp;gt; Swift Packages, and paste the URL of your dependency's git repository. For example: "&lt;a href="https://github.com/getstream/stream-chat-swift" rel="noopener noreferrer"&gt;https://github.com/getstream/stream-chat-swift&lt;/a&gt;".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FdevTOtz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FdevTOtz.png" alt="Screenshot shows Xcode with the Add Package Dependency dialog opened and Stream Chat iOS SDK GitHub URL in the input field"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After pressing next, Xcode will look for the repository and automatically select the latest version tagged. If this version is compatible with the one you were using, you can press next. Otherwise, type the version you were using. After that, Xcode will download the dependency.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FisVLxfL.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FisVLxfL.png" alt="Screenshot shows an Xcode screen selecting a dependency version and an Xcode screen downloading that dependency"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A repository may contain multiple targets. If that's the case, you should select only the ones you use.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FySfnql7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FySfnql7.png" alt="Screenshot shows an Xcode screen with dependency targets to be selected"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After you press finish, it's done! Though, you must repeat this process for each dependency you had.&lt;/p&gt;

&lt;p&gt;It's possible that a dependency doesn't provide a &lt;code&gt;Package.swift&lt;/code&gt;. In that case, it can't be used with Swift Package Manager. However, you can clone the repository and add &lt;code&gt;Package.swift&lt;/code&gt; yourself or request the maintainers to do so. For example, see the &lt;a href="https://github.com/GetStream/stream-chat-swift/commit/e406e5c406a92af42af308ee828eb582bd15ec6d#diff-f913940c58e8744a2af1c68b909bb6383e49007e6c5a12fb03104a9006ae677e" rel="noopener noreferrer"&gt;commit adding SPM support to the Stream Chat iOS SDK&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I hope you were successful in transitioning your project to the future. It's only getting better from now on. If you need any help converting your project to Swift Package Manager, feel free to reach out to me on Twitter: &lt;a href="https://twitter.com/cardosodev" rel="noopener noreferrer"&gt;@cardosodev&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ios</category>
      <category>beginners</category>
      <category>tutorial</category>
      <category>swift</category>
    </item>
    <item>
      <title>How to Use an SDK Built for UIKit in Your SwiftUI App</title>
      <dc:creator>Matheus Cardoso</dc:creator>
      <pubDate>Wed, 11 Nov 2020 17:31:38 +0000</pubDate>
      <link>https://dev.to/cardoso/how-to-use-an-sdk-built-for-uikit-in-your-swiftui-app-31k</link>
      <guid>https://dev.to/cardoso/how-to-use-an-sdk-built-for-uikit-in-your-swiftui-app-31k</guid>
      <description>&lt;p&gt;SwiftUI becomes more popular as it gets more capable with each iOS release. However, it may take some time until it's a better option than UIKit to build complex user experiences such as &lt;a href="https://getstream.io/chat/"&gt;chat&lt;/a&gt; and &lt;a href="https://dolby.io/products/interactivity-apis"&gt;video calls&lt;/a&gt;. That doesn't mean you need to stick with UIKit until all the SDKs you use support SwiftUI. In this tutorial, you'll learn how easy it is to use SDKs built for UIKit in your SwiftUI app.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qaW80FDe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.imgur.com/S9pYHXD.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qaW80FDe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.imgur.com/S9pYHXD.png" alt="Image shows a chat screen running inside a SwiftUI app" width="800" height="1484"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this tutorial, I'll use &lt;a href="https://github.com/getstream/stream-chat-swift"&gt;Stream Chat's iOS SDK&lt;/a&gt; inside a SwiftUI app. It provides a fully-featured chat user interface in the form of a &lt;code&gt;UIViewController&lt;/code&gt; subclass. If you're using a different SDK, the process may be similar if it provides the UI components in the form of UIKit views or view controllers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring the SDK
&lt;/h2&gt;

&lt;p&gt;Typically, in UIKit, we would put any SDK initialization code inside the AppDelegate's method &lt;code&gt;applicationDidFinishLaunching(_:)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you chose to go full SwiftUI and used the SwiftUI App lifecycle, which doesn't contain an AppDelegate, the best place to configure the SDK is inside the App struct's initializer:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  Wrapping a UIViewController in SwiftUI
&lt;/h2&gt;

&lt;p&gt;To display the &lt;code&gt;ChatViewController&lt;/code&gt; provided by the Stream Chat SDK, we need to wrap it in a SwiftUI view struct. To do this, create a struct that conforms to the protocol &lt;code&gt;UIViewControllerRepresentable&lt;/code&gt; and inside the &lt;code&gt;makeUIViewController&lt;/code&gt; function, instantiate and configure the view controller as you would in a UIKit app. Additionally, you can add properties to the SwiftUI view, as I did below with &lt;code&gt;channelType&lt;/code&gt; and &lt;code&gt;channelId&lt;/code&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  Displaying the UIViewController
&lt;/h2&gt;

&lt;p&gt;Now, you can use the SwiftUI view you created as you would any other SwiftUI view. In this case, I added it as the root view in my app's &lt;code&gt;ContentView&lt;/code&gt;. If you added any properties to your wrapper, you need to pass them now.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  Wrapping a UIView in SwiftUI
&lt;/h2&gt;

&lt;p&gt;In some cases, you may want to use a single &lt;code&gt;UIView&lt;/code&gt;. The process is similar to wrapping a &lt;code&gt;UIViewController&lt;/code&gt;. To do it, create a struct that conforms to &lt;code&gt;UIViewRepresentable&lt;/code&gt; and inside the &lt;code&gt;makeUIView&lt;/code&gt; function, instantiate and configure the view as you would in a UIKit app. In this case, I'm wrapping Stream Chat's &lt;code&gt;AvatarView&lt;/code&gt;. I also added the &lt;code&gt;name&lt;/code&gt; property to make it customize it inside the SwiftUI view hierarchy.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  Displaying the UIView
&lt;/h2&gt;

&lt;p&gt;Displaying the wrapped UIView is also similar to displaying the wrapped UIViewController. Just reference it as you would any other SwiftUI view. If you also added properties, make sure to fill them out.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  Next Steps with UIKit on SwiftUI
&lt;/h2&gt;

&lt;p&gt;Congratulations! You now have the entire library of SDKs built for UIKit at your SwiftUI app's disposal. If you want to check out two great examples of SDKs built for UIKit that you can use in your SwiftUI apps, see &lt;a href="https://getstream.io/tutorials/ios-chat/"&gt;Stream Chat's iOS SDK&lt;/a&gt; and &lt;a href="https://dolby.io/products/interactivity-apis"&gt;Dolby.io's Audio and Video SDK&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>End-to-End Encrypted iOS Chat with Apple's CryptoKit</title>
      <dc:creator>Matheus Cardoso</dc:creator>
      <pubDate>Fri, 06 Nov 2020 18:05:34 +0000</pubDate>
      <link>https://dev.to/cardoso/end-to-end-encrypted-ios-chat-with-apple-s-cryptokit-34b8</link>
      <guid>https://dev.to/cardoso/end-to-end-encrypted-ios-chat-with-apple-s-cryptokit-34b8</guid>
      <description>&lt;p&gt;In most cases, when building a chat app, it's essential to provide adequate privacy and security to your users. This can be done using cryptographic methods such as end-to-end encryption. End-to-end encryption is becoming a mainstream expectation, as it's featured in the biggest chat apps, such as WhatsApp and Telegram.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2F7aTLaWG.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2F7aTLaWG.png" alt="Image shows two chat screens, one with messages encrypted and the other with messages decrypted"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this article, you'll learn how basic end-to-end encryption works in an iOS chat app using Apple's own CryptoKit framework for its secure and high-level encryption methods and &lt;a href="https://getstream.io/tutorials/ios-chat/" rel="noopener noreferrer"&gt;Stream's flexible iOS chat SDK&lt;/a&gt; for its ready-made chat networking and UI components.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Please note that this tutorial is very basic and strictly educational, may contain simplifications, and rolling your own encryption protocol is not advisable. The algorithms used can contain certain 'gotchas' if not employed properly with the help of security professionals. Still, reading this article is a great start to get practical knowledge.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can find the completed project on GitHub: &lt;a href="https://github.com/GetStream/encrypted-ios-chat" rel="noopener noreferrer"&gt;encrypted-ios-chat&lt;/a&gt;. And if you have any questions, feel free to reach out to me on Twitter: &lt;a href="https://twitter.com/cardosodev" rel="noopener noreferrer"&gt;@cardosodev&lt;/a&gt; :).&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is End-to-End Encryption?
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;End-to-end encryption is a communication system where the only people who can read the messages are the people communicating. No eavesdropper can access the cryptographic keys needed to decrypt the conversation—not even a company that runs the messaging service.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.wired.com/2014/11/hacker-lexicon-end-to-end-encryption/" rel="noopener noreferrer"&gt;Hacker Lexicon: What Is End-to-End Encryption&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What Is Apple's CryptoKit?
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;CryptoKit is a new Swift framework that makes it easier and safer than ever to perform cryptographic operations, whether you simply need to compute a hash or are implementing a more advanced authentication protocol.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.apple.com/videos/play/wwdc2019/709/" rel="noopener noreferrer"&gt;WWDC19: Cryptography and Your Apps&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.wired.com/2014/11/hacker-lexicon-end-to-end-encryption/" rel="noopener noreferrer"&gt;Hacker Lexicon: What Is End-to-End Encryption&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What You Need
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Xcode 11 or later&lt;/li&gt;
&lt;li&gt;iOS 13 or later&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://getstream.io/accounts/signup/" rel="noopener noreferrer"&gt;Stream&lt;/a&gt; account&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Basic Encryption Methods
&lt;/h2&gt;

&lt;p&gt;Before we get to the chat part, let's start by defining the basic encryption methods we need. We'll integrate these methods in the next section.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Generating a Private Key
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;private key&lt;/strong&gt; is essential to end-to-end encryption. It is used alongside a &lt;strong&gt;public key&lt;/strong&gt; to generate a &lt;strong&gt;symmetric key&lt;/strong&gt; which is used for &lt;strong&gt;encryption&lt;/strong&gt; and &lt;strong&gt;decryption&lt;/strong&gt; of data. Each user in your application has a private and public key. They share their public keys with each other so that they can generate the same symmetric key. Alice shares her public key with Bob, and Bob uses his private key and Alice's public key to generate a symmetric key. Conversely, Bob shares his public key with Alice, and Alice uses her private key with Bob's public key to generate the same symmetric key. As long as Alice's and Bob's private keys are a secret to each of them, no one can generate the same symmetric key to decrypt their conversations.&lt;/p&gt;

&lt;p&gt;To generate a private key, we'll use the &lt;code&gt;P256.KeyAgreement.PrivateKey()&lt;/code&gt; initializer.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Additionally, I chose the P256 algorithm for its cross-platform availability, as it is supported by the &lt;a href="https://www.w3.org/TR/WebCryptoAPI/#dfn-NamedCurve-p256" rel="noopener noreferrer"&gt;Web Crypto API&lt;/a&gt; in case you need a web version. Also, it's a good balance between performance and security. This preference can change with time as new algorithms become available.&lt;/p&gt;

&lt;p&gt;PS: The public key can be extracted from the private key using &lt;code&gt;privateKey.publicKey&lt;/code&gt;. We'll touch on this in the integration part of this article.&lt;/p&gt;

&lt;p&gt;The private key must be saved somewhere safe. In order to do this, you may need to turn it into a string format to save it and back to perform the cryptographic operations. You can do this with the following &lt;code&gt;exportPrivateKey&lt;/code&gt; method:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;And the &lt;code&gt;importPrivateKey&lt;/code&gt; method:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h3&gt;
  
  
  2. Deriving Symmetric Key
&lt;/h3&gt;

&lt;p&gt;Once a user (message sender) has the public key of the other user it wants to communicate with (message recipient), that user can generate the symmetric key using the methods: &lt;code&gt;privateKey.sharedSecretFromKeyAgreement(with: publicKey)&lt;/code&gt; and &lt;code&gt;sharedSecret.hkdfDerivedSymmetricKey&lt;/code&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;This process is called a &lt;a href="https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange" rel="noopener noreferrer"&gt;Diffie-Hellman Key Exchange&lt;/a&gt; and ensures the symmetric key can be shared between two users without ever leaving their devices.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Encrypt Text
&lt;/h3&gt;

&lt;p&gt;Now, we use that symmetric key for encrypting texts using the &lt;code&gt;AES.GCM.seal&lt;/code&gt; method. We also encode it in a Base64 string, so it can be sent as normal text using the &lt;a href="https://getstream.io/chat/" rel="noopener noreferrer"&gt;Stream Chat&lt;/a&gt; SDK in the integration step.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;After the text is encrypted and encoded, it can be safely sent through the network.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Decrypt Text
&lt;/h3&gt;

&lt;p&gt;After the recipient receives the encrypted text, they will decode it from Base64 and decrypt it using the &lt;code&gt;AES.GCM.SealedBox&lt;/code&gt; and &lt;code&gt;AES.GCM.open&lt;/code&gt; methods.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;After the text is decrypted, it should be readable and can be displayed in the UI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stream Chat Integration
&lt;/h2&gt;

&lt;p&gt;In this section, you'll learn how to use the methods implemented above to achieve end-to-end encryption with &lt;a href="https://github.com/getstream/stream-chat-swift" rel="noopener noreferrer"&gt;Stream Chat's Swift SDK&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FvLa7014.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FvLa7014.png" alt="Image shows the stream chat swift SDK banner image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can follow the "iOS Chat SDK Setup" step in the &lt;a href="https://getstream.io/tutorials/ios-chat" rel="noopener noreferrer"&gt;official tutorial&lt;/a&gt; to get a basic chat app working in minutes.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Public Key Extra Data
&lt;/h3&gt;

&lt;p&gt;We need to define a custom &lt;code&gt;publicKey&lt;/code&gt; field for the User object so that users can share their public key with others. To do this, create the &lt;code&gt;PublicKeyExtraData&lt;/code&gt; type.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;After that, you should set the &lt;code&gt;User.extraDataType&lt;/code&gt; to &lt;code&gt;PublicKeyExtraData.self&lt;/code&gt; before you initialize the Stream Chat Client in &lt;code&gt;AppDelegate.swift&lt;/code&gt;:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h3&gt;
  
  
  2. Custom Set User Method
&lt;/h3&gt;

&lt;p&gt;Now, let's define our custom &lt;code&gt;setUser&lt;/code&gt; method so that the user can be registered in Stream Chat alongside its public key.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Additionally, the public key must be exported in a string format. You should define an &lt;code&gt;exportPublicKey&lt;/code&gt; method to do this.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;We're percent-encoding the public key after encoding to base64 to ensure the + sign is not ignored in case the public key is used in the URLs of specific requests.&lt;/p&gt;

&lt;p&gt;In a future step, after we fetch another user's public key, we'll need to use the &lt;code&gt;importPublicKey&lt;/code&gt; method, which does the reverse of the &lt;code&gt;exportPublicKey&lt;/code&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h3&gt;
  
  
  3. Encrypted Chat View Controller
&lt;/h3&gt;

&lt;p&gt;Now that we generated the private key and registered our user with a public key, we need a custom &lt;code&gt;ChatViewController&lt;/code&gt; that encrypts messages before sending and decrypts messages before displaying.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FPj5atA3.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FPj5atA3.gif" alt="Animation shows an encrypted chat screen alternating every second between encrypted and decrypted messages"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To do this, let's create the &lt;code&gt;EncryptedChatViewController&lt;/code&gt;, which inherits from &lt;code&gt;ChatViewController&lt;/code&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;As you can see, it contains an additional &lt;code&gt;symmetricKey&lt;/code&gt; property, which will be used for the encryption and decryption. In the &lt;code&gt;viewDidLoad&lt;/code&gt; we set the &lt;code&gt;messagePreparationCallback&lt;/code&gt;, which encrypts the messages before they're sent. We also override the &lt;code&gt;messageCell&lt;/code&gt; method to decrypt the message before displaying it.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Present Encrypted Chat
&lt;/h3&gt;

&lt;p&gt;After implementing our custom &lt;code&gt;ChatViewController&lt;/code&gt;, now we can present it.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;To present the &lt;code&gt;EncryptedChatViewController&lt;/code&gt;, we query the user we want to communicate with to get its public key and generate a symmetric key. After that, we set the &lt;code&gt;symmetricKey&lt;/code&gt; and &lt;code&gt;presenter&lt;/code&gt; properties and push the view controller into the navigation stack.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next Steps With CryptoKit
&lt;/h2&gt;

&lt;p&gt;Congratulations! You just learned how to implement basic end-to-end encryption in your iOS chat apps. It's important to know this is the most basic form of end-to-end encryption. It lacks some additional tweaks that can make it more bullet-proof for the real world, such as &lt;a href="https://en.wikipedia.org/wiki/Padding_(cryptography)#Randomized_padding" rel="noopener noreferrer"&gt;randomized padding&lt;/a&gt;, &lt;a href="https://en.wikipedia.org/wiki/Digital_signature" rel="noopener noreferrer"&gt;digital signature&lt;/a&gt;, and &lt;a href="https://en.wikipedia.org/wiki/Forward_secrecy" rel="noopener noreferrer"&gt;forward secrecy&lt;/a&gt;, among others. Also, for real-world usage, it's vital to get the help of application security professionals.&lt;/p&gt;

</description>
      <category>ios</category>
      <category>security</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Choose Your iOS Dependencies Wisely</title>
      <dc:creator>Matheus Cardoso</dc:creator>
      <pubDate>Thu, 22 Oct 2020 14:31:46 +0000</pubDate>
      <link>https://dev.to/cardoso/choose-your-ios-dependencies-wisely-49j0</link>
      <guid>https://dev.to/cardoso/choose-your-ios-dependencies-wisely-49j0</guid>
      <description>&lt;p&gt;Dependencies are vital for most iOS projects. They allow us to speed up development and not reinvent the wheel every time we need components such as &lt;a href="https://github.com/Alamofire/Alamofire" rel="noopener noreferrer"&gt;networking&lt;/a&gt;, &lt;a href="https://github.com/airbnb/lottie-ios" rel="noopener noreferrer"&gt;rendering&lt;/a&gt;, &lt;a href="https://github.com/getstream/stream-chat-swift" rel="noopener noreferrer"&gt;chat&lt;/a&gt;, &lt;a href="https://github.com/WenchaoD/FSCalendar" rel="noopener noreferrer"&gt;calendar&lt;/a&gt;, and &lt;a href="https://swiftpackageindex.com/" rel="noopener noreferrer"&gt;many others&lt;/a&gt; which can be common to different types of projects. It's also an efficient way of deferring code maintenance to a &lt;a href="https://getstream.io/chat/" rel="noopener noreferrer"&gt;company&lt;/a&gt; or &lt;a href="https://vapor.codes/" rel="noopener noreferrer"&gt;open source community&lt;/a&gt;, since they'll fix bugs, add new features, and update the code for you. Using dependencies, we're able to focus our working hours on what sets our iOS app apart from the rest.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FDwn6y7Z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FDwn6y7Z.png" alt="Image shows the icons of Carthage, CocoaPods, and Swift Package Manager"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, any seasoned iOS developer knows dependencies can often hold your iOS project back and negate the time saved if you don't choose them wisely.&lt;/p&gt;

&lt;p&gt;Fortunately, there are rules which you can follow when choosing iOS dependencies to avoid most, if not all, of the downsides. In this post, I present five rules for iOS dependencies that can save you many hassles in the future.&lt;/p&gt;

&lt;h2&gt;
  
  
  Open-Source or Source-Available
&lt;/h2&gt;

&lt;p&gt;You should always prefer using dependencies that are Open-Source or Source-Available. These will allow you greater freedom to accommodate changes in requirements, fix bugs yourself, step through code, and debug things easily. It will also help you find out undocumented behaviors, know what it does for sure, and not risk undesired malicious code or analytics to run in your apps.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FqRbOyKt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FqRbOyKt.png" alt="Image shows an Xcode window browsing and debugging code inside a dependency"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Closed-Source dependencies distributed in a compiled format such as &lt;code&gt;.xcframework&lt;/code&gt;, are an opaque box. It's hard to know for sure what it's doing. What data is it collecting? What is it sending to the server? Can it crash my app under certain circumstances outside my control? How long will the maintainer take to fix a bug?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2Fas7t9Au.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2Fas7t9Au.png" alt="Image shows an Xcode window selecting a .xcframework without any other info or code available"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Closed-Source SDKs are constantly harming productivity and reducing the choices that iOS developers can make. For example, &lt;a href="https://9to5mac.com/2020/07/10/app-crash-facebook-sdk/" rel="noopener noreferrer"&gt;Facebook's iOS SDKs frequently crash other apps for no good reason&lt;/a&gt;, without any possibility for developers to act on it other than removing the SDK altogether. Another &lt;a href="https://www.tiforense.com.br/popular-ios-sdk-caught-spying-on-billions-of-users-and-committing-ad-fraud/" rel="noopener noreferrer"&gt;SDK was found to steal user data and attempt to cover its tracks&lt;/a&gt;. They're best avoided if there are competent alternatives.&lt;/p&gt;

&lt;h2&gt;
  
  
  Active Development
&lt;/h2&gt;

&lt;p&gt;Before you decide on a dependency, check how long ago its last updates were made. If it's days or weeks, it's more likely that it's compatible with the latest iOS versions, and you'll be able to count on updates for a while. It's also more likely that the maintainers are still around to help if you have a question.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FGmVjepC.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FGmVjepC.png" alt="Image shows a GitHub repository in active development"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the other hand, if it's been months or years since the last updates, you should consider not using this dependency. It's unlikely that it's still compatible with the latest iOS or Swift versions, and even less likely that the maintainer is around to help you or provide any new updates.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FLqI98Xp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FLqI98Xp.png" alt="Image shows a GitHub repository without activity for eight years"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Inactive projects are generally bug-ridden and should be avoided, but it's still possible to use them if you're willing to fork them, fix the bugs you encounter, and become a maintainer. However, most of the time, it can be more productive to build the component you need from scratch. &lt;/p&gt;

&lt;h2&gt;
  
  
  Built with Swift
&lt;/h2&gt;

&lt;p&gt;Swift has been around for five years. It's now considered a mature language and has greatly increased productivity and code correctness over its ancestor, Objective-C. It's no mystery that these improvements are carried over to the dependencies you use. Dependencies built with Swift are likely to be more stable and fit in seamlessly with the Swifty patterns and features developers know and love, such as &lt;a href="https://www.raywenderlich.com/6742901-protocol-oriented-programming-tutorial-in-swift-5-1-getting-started" rel="noopener noreferrer"&gt;protocol oriented programming&lt;/a&gt;, &lt;a href="https://docs.swift.org/swift-book/LanguageGuide/OptionalChaining.html" rel="noopener noreferrer"&gt;optionals&lt;/a&gt;, &lt;a href="https://docs.swift.org/swift-book/LanguageGuide/Generics.html" rel="noopener noreferrer"&gt;generics&lt;/a&gt;, &lt;a href="https://docs.swift.org/swift-book/LanguageGuide/CollectionTypes.html" rel="noopener noreferrer"&gt;collection types&lt;/a&gt;, &lt;a href="https://docs.swift.org/swift-book/LanguageGuide/Functions.html" rel="noopener noreferrer"&gt;first class functions&lt;/a&gt;, and others.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FKfhadkB.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FKfhadkB.png" alt="Image shows Swift logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Alternatively, if you choose to use a dependency written in Objective-C, you'll likely run into old patterns and naming conventions that are not as nice to work with. Objective-C dependencies are also more likely to contains bugs related to null references.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2Fh2fO33d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2Fh2fO33d.png" alt="Image shows Objective-C logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's not a complete deal breaker if a dependency is written in Objective-C, as long as it's still actively maintained. Yet, I've found that every Objective-C dependency I wanted to use had an excellent and newer alternative written in Swift. For example, over the years, I've replaced &lt;a href="https://github.com/SDWebImage/SDWebImage" rel="noopener noreferrer"&gt;SDWebImage&lt;/a&gt; with &lt;a href="https://github.com/kean/Nuke" rel="noopener noreferrer"&gt;Nuke&lt;/a&gt; in almost all my projects with great benefit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Company-Maintained
&lt;/h2&gt;

&lt;p&gt;Dependencies that are maintained by a company tend to be more reliable when compared to dependencies that are supported by a community. It's less likely that a company-maintained SDK or library will be abandoned if it's vital to that company's business.&lt;/p&gt;

&lt;p&gt;For example, it's highly unlikely that a library like &lt;a href="https://github.com/realm/realm-cocoa" rel="noopener noreferrer"&gt;Realm&lt;/a&gt; or &lt;a href="https://github.com/Instagram/IGListKit" rel="noopener noreferrer"&gt;IGListKit&lt;/a&gt; will be abandoned, as they're maintained by a business as well as an active community. In some cases, companies may also offer dedicated support in case you need the extra commitment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Welcoming Community
&lt;/h2&gt;

&lt;p&gt;A welcoming community also goes a long way in ensuring a smooth experience with an SDK or library. Most of the time, except for company support or paid support plans, you'll rely on this community to help you when you're having problems or when you want to contribute back to the project. If it's a community that is patient with newcomers and is receptive to new ideas, then you're more likely to have a good time depending on them. &lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;These are the characteristics I look for when searching for iOS libraries and SDKs. It's challenging to find a library which checks all these boxes, but keeping these in mind helps compare the options and choose the one that will give you fewer problems in the future.&lt;/p&gt;

</description>
      <category>ios</category>
      <category>swift</category>
      <category>beginners</category>
      <category>tips</category>
    </item>
    <item>
      <title>Build a Psychotherapy App with Video and Chat for iOS</title>
      <dc:creator>Matheus Cardoso</dc:creator>
      <pubDate>Thu, 15 Oct 2020 15:03:43 +0000</pubDate>
      <link>https://dev.to/cardoso/build-a-psychotherapy-app-with-video-and-chat-for-ios-198j</link>
      <guid>https://dev.to/cardoso/build-a-psychotherapy-app-with-video-and-chat-for-ios-198j</guid>
      <description>&lt;p&gt;In this guide, we'll create the a basic Psychotherapy App for iOS with &lt;a href="https://getstream.io/chat/" rel="noopener noreferrer"&gt;Stream Chat&lt;/a&gt;, for its &lt;a href="https://getstream.io/tutorials/ios-chat/" rel="noopener noreferrer"&gt;fully featured chat components&lt;/a&gt;, and Dolby.io, for its excellent audio and video capabilities. Both offerings are &lt;a href="https://getstream.io/blog/hipaa-compliant-chat-apps/" rel="noopener noreferrer"&gt;HIPAA compliant&lt;/a&gt;. When you finish following the steps, you'll get an app like in the image below. Additionally, it will be compatible with iOS's light and dark mode features.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FUhqVsv0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FUhqVsv0.png" alt="Image shows two screenshots, one from the chat screen with a small video overlay with the therapist, and another with a fullscreen video of the therapist"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you get lost while following this guide, you can get the completed Xcode project in this GitHub repo: &lt;a href="https://github.com/getstream/psychotherapy-app-ios" rel="noopener noreferrer"&gt;psychotherapy-app-ios&lt;/a&gt;. Let's get started with our teletherapy app development!&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Stream Chat?
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Build real-time chat in less time. Rapidly ship in-app messaging with our highly reliable chat infrastructure. Drive in-app conversion, engagement, and retention with the Stream Chat messaging platform API &amp;amp; SDKs.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://getstream.io/chat/" rel="noopener noreferrer"&gt;Stream Chat &amp;amp; Messaging&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What is Dolby.io's Client SDK?
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Dolby Interactivity APIs provide a platform for unified communications and collaboration. In-flow communications refers to the combination of voice, video, and messaging integrated into your application in a way that is cohesive for your end-users. This is in contrast to out-of-app communications where users must stop using your application and instead turn to third-party tools.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dolby.io/developers/interactivity-apis/client-sdk/overview" rel="noopener noreferrer"&gt;Dolby.io Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Xcode 11 or later&lt;/li&gt;
&lt;li&gt;iOS 13 or later&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://getstream.io/accounts/signup/" rel="noopener noreferrer"&gt;Stream&lt;/a&gt; account&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://dolby.io/signup/" rel="noopener noreferrer"&gt;Dolby.io&lt;/a&gt; account&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Set Up Project
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Create the Xcode Project
&lt;/h3&gt;

&lt;p&gt;First, we open Xcode and create an iOS App project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2Fm4OIEuW.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2Fm4OIEuW.png" alt="Screenshot shows an iOS app created on Xcode 12"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And make sure to select 'Storyboard' for the User Interface.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install Dependencies
&lt;/h3&gt;

&lt;p&gt;To install the &lt;a href="https://github.com/getstream/stream-chat-swift" rel="noopener noreferrer"&gt;Stream Chat&lt;/a&gt; and &lt;a href="https://github.com/voxeet/voxeet-sdk-ios" rel="noopener noreferrer"&gt;Dolby.io's Client SDK&lt;/a&gt; dependencies, we'll use &lt;a href="https://cocoapods.org/" rel="noopener noreferrer"&gt;CocoaPods&lt;/a&gt;. If you prefer Carthage, both frameworks support it as well.&lt;/p&gt;

&lt;p&gt;In the folder where you saved the project, run &lt;code&gt;pod init&lt;/code&gt; and add &lt;code&gt;StreamChat&lt;/code&gt; and &lt;code&gt;VoxeetUXKit&lt;/code&gt; to the &lt;code&gt;Podfile&lt;/code&gt;. It should look similar to this:&lt;/p&gt;

&lt;p&gt;Note: if you're not seeing the Podfile below due to a bug in dev.to, refresh this page.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;After you do that, run &lt;code&gt;pod install&lt;/code&gt;, wait a bit for it to finish, and open the project via the &lt;code&gt;.xcworkspace&lt;/code&gt; that was created.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure the Stream Chat Dashboard
&lt;/h2&gt;

&lt;p&gt;Sign up at &lt;a href="https://getstream.io" rel="noopener noreferrer"&gt;GetStream.io&lt;/a&gt;, create the application, and make sure to select development instead of production.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fo6nhrm361eeh7qkhla8q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fo6nhrm361eeh7qkhla8q.png" alt="Screenshot of a user creating a development application at GetStream.io"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To make things simple for now, let's disable both auth checks and permission checks. Make sure to hit save. When your app is in production, you should keep these enabled.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fir0vtvh2rgowvy0lohn0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fir0vtvh2rgowvy0lohn0.png" alt="Screenshot of skip auth checks and permission being enabled in a Stream App dashboard"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For more information, visit the &lt;a href="https://getstream.io/chat/docs/tokens_and_authentication/?language=swift" rel="noopener noreferrer"&gt;documentation about authentication&lt;/a&gt; and &lt;a href="https://getstream.io/chat/docs/chat_permission_policies/?language=swift" rel="noopener noreferrer"&gt;permissions&lt;/a&gt;.  &lt;/p&gt;

&lt;p&gt;Now, save your Stream credentials, as we'll need them to configure the chat in the app. Since we disabled auth and permissions, we'll only really need the key for now, but in production, you'll use the secret in your backend to &lt;a href="https://getstream.io/docs/auth_and_permissions/" rel="noopener noreferrer"&gt;implement proper authentication to issue user tokens for Stream Chat&lt;/a&gt;, so users can interact with your app securely.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1bl76070ym1iiw211wef.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1bl76070ym1iiw211wef.png" alt="Screenshot of credentials on stream dashboard"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, I've censored my keys. You should make sure to keep your credentials secure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure the Dolby.io Dashboard
&lt;/h2&gt;

&lt;p&gt;Configuring the &lt;a href="https://dolby.io" rel="noopener noreferrer"&gt;Dolby.io&lt;/a&gt; dashboard is simpler. Just create an account there, and it should already set up an initial application for you.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ffq770ahudm7o49ek3dmb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ffq770ahudm7o49ek3dmb.png" alt="Screenshot of credentials on dolby.io dashboard"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, save your credentials, as we'll need them to power the audio and video streaming in the app. As with the Stream credentials, you use these for development. In production, you'll need to set up proper authentication. It's described in detail &lt;a href="https://dolby.io/developers/interactivity-apis/client-sdk/initializing#secure-authentication" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure Stream Chat and Dolby.io's SDKs
&lt;/h2&gt;

&lt;p&gt;The first step with code is to configure the Stream and Dolby SDK with the credentials from the dashboards. Open the &lt;code&gt;AppDelegate.swift&lt;/code&gt; file and modify it, so it looks similar to this:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;That code initializes the Dolby.io and Stream Chat SDKs with credentials you got in the previous two steps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create the Join Screen
&lt;/h2&gt;

&lt;p&gt;Let's start building the "Join" screen. This screen consists of two &lt;code&gt;UIButton&lt;/code&gt; instances. One to join as the Patient, and the other to join as the Therapist. This is, of course, an oversimplification to make this tutorial short and get to the chat, audio, and video features faster. In your complete app, you'll need proper registration, database, and all that. For this tutorial, the screen will look similar to the screenshot below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FCPuimJv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FCPuimJv.png" alt="Screenshot shows an app with two buttons, one to join as the patient, and the other to join as the therapist"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Go to the storyboard, select the default view controller, and click &lt;code&gt;Editor &amp;gt; Embed In &amp;gt; Navigation Controller&lt;/code&gt;. That will place it under a navigation controller, which we'll use to navigate to the channel screen.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FNGJnVi8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FNGJnVi8.png" alt="Image shows storyboard with a JoinViewController embedded in a navigation controller"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Make sure to rename &lt;code&gt;ViewController&lt;/code&gt; to &lt;code&gt;JoinViewController&lt;/code&gt;, so you don't get confused later on. You can do this easily by right-clicking on &lt;code&gt;ViewController&lt;/code&gt; in &lt;code&gt;ViewController.swift&lt;/code&gt; and selecting &lt;code&gt;refactor&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To make things simple, let's leave the storyboard like this and use only code from now on. To set up the two buttons, we need the following code in &lt;code&gt;JoinViewController.swift&lt;/code&gt;:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;That code sets up the views, the constraints, and the handlers we need. Let's start by extending &lt;code&gt;JoinViewController&lt;/code&gt; to define &lt;code&gt;setupViews&lt;/code&gt;:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;That code will create the buttons and add them to the controller's view. Next, we need to define constraints between the three. Let's do this by extending &lt;code&gt;JoinViewController&lt;/code&gt; to define &lt;code&gt;setupConstraints&lt;/code&gt;:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;That code will make sure the &lt;code&gt;patientButton&lt;/code&gt; stays in the center of the screen and the &lt;code&gt;therapistButton&lt;/code&gt; below it. Now we need to set up the handler for when the user presses the buttons. Let's do this again by extending the controller to define &lt;code&gt;setupHandlers&lt;/code&gt;:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;That code will make it so when the user presses the button a &lt;code&gt;TherapyViewController&lt;/code&gt; is created and set up for the therapist or patient, depending on which button was pressed. We'll create &lt;code&gt;TherapyViewController&lt;/code&gt; in the next step.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create the Therapy Screen
&lt;/h2&gt;

&lt;p&gt;Now, let's create the screen where the patient and therapist will talk via chat and where they can begin a video call. We'll start by defining TherapyViewController. It will look similar to the screenshots below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FyEzg0Th.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FyEzg0Th.png" alt="Image shows two screenshots of a conversation in a chat screen, one from the perspective of the patient, and the other from the perspective of the therapist"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The first step is to create a TherapyViewController.swift file and paste the code below.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;That code defines a subclass of ChatViewController, which provides most of the chat behavior and UI we need. It also defines the patient and therapist &lt;code&gt;User&lt;/code&gt; objects and a &lt;code&gt;Channel&lt;/code&gt; object between the two. These objects will be used to interact with the Stream API. On &lt;code&gt;viewDidLoad&lt;/code&gt;, we also call &lt;code&gt;setupViews&lt;/code&gt; and &lt;code&gt;setupHandlers&lt;/code&gt; to set up the views and handlers needed. We'll define those functions next.&lt;/p&gt;

&lt;p&gt;But, let's first define the &lt;code&gt;setupPatient&lt;/code&gt; function that sets the current Stream Chat user as the patient, and the &lt;code&gt;setupTherapist&lt;/code&gt; function that sets it as the therapist.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Now we define &lt;code&gt;setupViews&lt;/code&gt; to set up the views we need.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Those functions will display a button which starts a call. For it to work, we'll need to define &lt;code&gt;setupHandlers&lt;/code&gt; as well.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Those functions set &lt;code&gt;callButtonPressed&lt;/code&gt; as the function to be called when the call button is pressed, which in turn calls &lt;code&gt;startCall&lt;/code&gt;, which we define next.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Finally, that function uses the Dolby.io SDK to start a conference call.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure Usage Descriptions
&lt;/h2&gt;

&lt;p&gt;If you use the app now, you'll be able to chat, but pressing the call button will crash the application. That happens because we need to configure the usage descriptions for microphone and video in the &lt;code&gt;Info.plist&lt;/code&gt; file. To do this, just open &lt;code&gt;Info.plist&lt;/code&gt; and set the &lt;code&gt;NSMicrophoneUsageDescription&lt;/code&gt; and &lt;code&gt;NSCameraUsageDescription&lt;/code&gt; keys as pictured below. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FehlswCF.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FehlswCF.png" alt="Image shows the Info.plist file with the two usage descriptions defined"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, we open the app in two devices, and, from the chat, we can start a call.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FUhqVsv0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FUhqVsv0.png" alt="Image shows two screenshots, one from the chat screen with a small video overlay with the therapist, and another with a fullscreen video of the therapist"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Next Steps with the Psychotherapy App
&lt;/h2&gt;

&lt;p&gt;Congratulations! You've built the basis of a functioning psychotherapy app with Stream Chat and Dolby.io. I encourage you to browse through &lt;a href="https://getstream.io/chat/docs/introduction/?language=swift" rel="noopener noreferrer"&gt;Stream Chat's docs&lt;/a&gt;, &lt;a href="https://dolby.io/developers/interactivity-apis/client-sdk/overview" rel="noopener noreferrer"&gt;Dolby.io's docs&lt;/a&gt;, and experiment with the project you just built. If you're interested in the business side of things, read about how &lt;a href="https://getstream.io/blog/hipaa-chat/" rel="noopener noreferrer"&gt;Stream Chat provides HIPAA compliance&lt;/a&gt; and how &lt;a href="https://dolby.io/pricing/interactivity-apis/" rel="noopener noreferrer"&gt;Dolby.io provides HIPAA compliance&lt;/a&gt;. Good luck on your teletherapy app development!&lt;/p&gt;

</description>
      <category>swift</category>
      <category>ios</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>End-to-End Encrypted Chat with the Web Crypto API</title>
      <dc:creator>Matheus Cardoso</dc:creator>
      <pubDate>Thu, 08 Oct 2020 13:26:05 +0000</pubDate>
      <link>https://dev.to/cardoso/end-to-end-encrypted-chat-with-the-web-crypto-api-3d02</link>
      <guid>https://dev.to/cardoso/end-to-end-encrypted-chat-with-the-web-crypto-api-3d02</guid>
      <description>&lt;p&gt;When transmitting or storing user data, especially private conversations, it's essential to consider employing cryptographic techniques to ensure privacy. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FlqSXw3K.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FlqSXw3K.gif" alt="Animation shows a chat screen with messages alternating from encrypted text to decrypted text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By reading this tutorial, you'll learn how to end-to-end encrypt data in web applications using nothing but JavaScript and the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API" rel="noopener noreferrer"&gt;Web Crypto API&lt;/a&gt;, which is a native browser API.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Please note that this tutorial is very basic and strictly educational, may contain simplifications, and rolling your own encryption protocol is not advisable. The algorithms used can contain certain 'gotchas' if not employed properly with the help of security professionals&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can also find the full project in this &lt;a href="https://github.com/GetStream/encrypted-web-chat" rel="noopener noreferrer"&gt;GitHub repo&lt;/a&gt; if you happen to get lost. And if you have any questions, feel free to reach out to me on &lt;a href="https://twitter.com/cardosodev" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; :).&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is End-to-End Encryption?
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;End-to-end encryption is a communication system where the only people who can read the messages are the people communicating. No eavesdropper can access the cryptographic keys needed to decrypt the conversation—not even a company that runs the messaging service.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.wired.com/2014/11/hacker-lexicon-end-to-end-encryption/" rel="noopener noreferrer"&gt;Hacker Lexicon: What Is End-to-End Encryption&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What Is the Web Crypto API?
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;The Web Cryptography API defines a low-level interface to interacting with cryptographic key material that is managed or exposed by user agents. The API itself is agnostic of the underlying implementation of key storage but provides a common set of interfaces that allow rich web applications to perform operations such as signature generation and verification, hashing and verification, encryption and decryption, without requiring access to the raw keying material.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.w3.org/TR/WebCryptoAPI/" rel="noopener noreferrer"&gt;W3C: Web Cryptography API&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Onto the Basics
&lt;/h2&gt;

&lt;p&gt;In the following steps, we'll declare the essential functions involved in end-to-end encryption. You can copy each one into a dedicated &lt;code&gt;.js&lt;/code&gt; file under a &lt;code&gt;lib&lt;/code&gt; folder. Note that all of them are &lt;code&gt;async&lt;/code&gt; functions due to the Web Crypto API's asynchronous nature.&lt;/p&gt;

&lt;p&gt;Note: Not all browsers implement the algorithms we'll use. Namely, Internet Explorer and Microsoft Edge. Check the compatibility table at &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto#Browser_compatibility" rel="noopener noreferrer"&gt;MDN web docs: Subtle Crypto - Web APIs&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generate a Key Pair
&lt;/h2&gt;

&lt;p&gt;Cryptographic key pairs are essential to end-to-end encryption. A &lt;strong&gt;key pair&lt;/strong&gt; consists of a &lt;strong&gt;public key&lt;/strong&gt; and a &lt;strong&gt;private key&lt;/strong&gt;. Each user in your application should have a key pair to protect their data, with the public component available to other users and the private component only accessible to the key pair's owner. You'll understand how these come into play in the next section.&lt;/p&gt;

&lt;p&gt;To generate the key pair, we'll use the &lt;a href="https://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-generateKey" rel="noopener noreferrer"&gt;&lt;code&gt;window.crypto.subtle.generateKey&lt;/code&gt;&lt;/a&gt; method, and export the private and public keys using &lt;a href="https://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-exportKey" rel="noopener noreferrer"&gt;&lt;code&gt;window.crypto.subtle.exportKey&lt;/code&gt;&lt;/a&gt; with the &lt;a href="https://tools.ietf.org/html/rfc7517" rel="noopener noreferrer"&gt;JWK format&lt;/a&gt;. The latter is needed to save or transmit these keys. Think of it as a way of serializing the keys for use outside of JavaScript.&lt;/p&gt;

&lt;p&gt;PS: if you don't see &lt;code&gt;generateKeyPair.js&lt;/code&gt; below due to a bug in dev.to, refresh this page.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Additionally, I chose the &lt;a href="https://www.w3.org/TR/WebCryptoAPI/#ecdh" rel="noopener noreferrer"&gt;ECDH algorith&lt;/a&gt; with the &lt;a href="https://en.wikipedia.org/wiki/Elliptic-curve_cryptography" rel="noopener noreferrer"&gt;P-256 elliptic curve&lt;/a&gt; as it is well supported and the right balance between security and performance. This preference can change with time as new algorithms become available.&lt;/p&gt;

&lt;p&gt;Note: exporting the private key can lead to security issues, so it must be handled carefully. The approach of allowing the user to copy and paste it that will be presented in the integration part of this tutorial is not a great practice and only done for educational purposes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Derive Key
&lt;/h2&gt;

&lt;p&gt;We'll use the key pair generated in the last step to derive the symmetric cryptographic key that encrypts and decrypts data and is unique for any two communicating users. For example, User A derives the key using their private key with User B's public key, and User B derives the same key using their private key and User A's public key. No one can generate the &lt;strong&gt;derived key&lt;/strong&gt; without access to at least one of the users' private keys, so it's essential to keep them safe.&lt;/p&gt;

&lt;p&gt;In the previous step, we exported the key pair in the JWK format. Before we can derive the key, we need to import those back to the original state using &lt;a href="https://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-importKey" rel="noopener noreferrer"&gt;&lt;code&gt;window.crypto.subtle.importKey&lt;/code&gt;&lt;/a&gt;. To derive the key, we'll use the &lt;a href="https://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-deriveKey" rel="noopener noreferrer"&gt;&lt;code&gt;window.crypto.subtle.deriveKey&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;In this case, I chose the &lt;a href="https://www.w3.org/TR/WebCryptoAPI/#aes-gcm" rel="noopener noreferrer"&gt;AES-GCM algorithm&lt;/a&gt; for its known security/performance balance and browser availability.&lt;/p&gt;

&lt;h2&gt;
  
  
  Encrypt Text
&lt;/h2&gt;

&lt;p&gt;Now we can use the derived key to &lt;strong&gt;encrypt&lt;/strong&gt; text, so it's safe to transmit it.&lt;/p&gt;

&lt;p&gt;Before encryption, we encode the text to a &lt;code&gt;Uint8Array&lt;/code&gt;, since that's what the encrypt function takes. We encrypt that array using &lt;a href="https://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-encrypt" rel="noopener noreferrer"&gt;&lt;code&gt;window.crypto.subtle.encrypt&lt;/code&gt;&lt;/a&gt;, and then we turn its &lt;code&gt;ArrayBuffer&lt;/code&gt; output back to  &lt;code&gt;Uint8Array&lt;/code&gt;, which we then turn to &lt;code&gt;string&lt;/code&gt; and encode it to &lt;a href="https://en.wikipedia.org/wiki/Base64" rel="noopener noreferrer"&gt;Base64&lt;/a&gt;. JavaScript makes it a little bit complicated, but this is just a way to turn our encrypted data into transmittable text. &lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;As you can see, the AES-GCM algorithm parameter includes an &lt;a href="https://en.wikipedia.org/wiki/Initialization_vector" rel="noopener noreferrer"&gt;initialization vector&lt;/a&gt; (iv). For every encryption operation, it can be random, but absolutely must be unique to ensure the strength of the encryption. It is included in the message so it can be used in the decryption process, which is the next step. Also, though unlikely to reach this number, you should discard the keys after 2^32 usages, as the random IV can repeat at that point. &lt;/p&gt;

&lt;h2&gt;
  
  
  Decrypt Text
&lt;/h2&gt;

&lt;p&gt;Now we can use the derived key to &lt;strong&gt;decrypt&lt;/strong&gt; any encrypted text we receive, doing precisely the opposite from the encrypt step.&lt;/p&gt;

&lt;p&gt;Before decryption, we retrieve the initialization vector, convert the string back from Base64, turn it into a &lt;code&gt;Uint8Array&lt;/code&gt;, and decrypt it using the same algorithm definition. After that, we decode the &lt;code&gt;ArrayBuffer&lt;/code&gt; and return the human-readable string.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;It's also possible that this decryption process will fail due to using a wrong derived key or initialization vector, which means the user does not have the correct key pair to decrypt the text they received. In such a case, we return an error message.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integrating in Your Chat App
&lt;/h2&gt;

&lt;p&gt;And that is all the cryptographic work required! In the following sections, I'll explain how I used the methods we implemented above to end-to-end encrypt a chat application built with &lt;a href="https://getstream.io/chat/react-chat/tutorial/" rel="noopener noreferrer"&gt;Stream Chat's powerful React chat components&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Clone the Project
&lt;/h2&gt;

&lt;p&gt;Clone the &lt;a href="https://github.com/getstream/encrypted-web-chat" rel="noopener noreferrer"&gt;encrypted-web-chat repository&lt;/a&gt; in a local folder, install the dependencies and run it.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;After that, a browser tab should open. But first, we need to configure the project with our own Stream Chat API key.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure the Stream Chat Dashboard
&lt;/h2&gt;

&lt;p&gt;Create your account at &lt;a href="https://getstream.io/" rel="noopener noreferrer"&gt;GetStream.io&lt;/a&gt;, create an application, and select development instead of production.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fo6nhrm361eeh7qkhla8q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fo6nhrm361eeh7qkhla8q.png" alt="Screenshot of a user creating a development application at GetStream.io"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To simplify, let's disable both auth checks and permission checks. Make sure to hit save. When your app is in production, you should keep these enabled and have a backend to provide tokens for the users.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fir0vtvh2rgowvy0lohn0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fir0vtvh2rgowvy0lohn0.png" alt="Screenshot of skip auth checks and permission enabled in a Stream App dashboard"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For future reference, see the &lt;a href="https://getstream.io/chat/docs/tokens_and_authentication/?language=js" rel="noopener noreferrer"&gt;documentation on authentication&lt;/a&gt; and the &lt;a href="https://getstream.io/chat/docs/chat_permission_policies/?language=js" rel="noopener noreferrer"&gt;documentation on permissions&lt;/a&gt;.  &lt;/p&gt;

&lt;p&gt;Please take note of the Stream credentials, as we'll use them to initialize the chat client in the app in the next step. Since we disabled authentication and permissions, we'll only really need the key for now. Still, in the future, you'll use the secret in your backend to &lt;a href="https://getstream.io/docs/auth_and_permissions/" rel="noopener noreferrer"&gt;implement authentication to issue user tokens for Stream Chat&lt;/a&gt;, so your chat app can have proper access controls.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1bl76070ym1iiw211wef.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1bl76070ym1iiw211wef.png" alt="Screenshot of credentials on stream dashboard"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, I've redacted my keys. It would be best if you kept these credentials safe.&lt;/p&gt;

&lt;h2&gt;
  
  
  Change the Credentials
&lt;/h2&gt;

&lt;p&gt;In &lt;a href="https://github.com/GetStream/encrypted-web-chat/blob/main/src/lib/chatClient.js" rel="noopener noreferrer"&gt;&lt;code&gt;src/lib/chatClient.js&lt;/code&gt;&lt;/a&gt;, change the key with yours. We'll use this object to make API calls and configure the chat components.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;After this, you should be able to test the application. In the following steps, you'll understand where the functions we defined fit in.&lt;/p&gt;

&lt;h2&gt;
  
  
  Set the User
&lt;/h2&gt;

&lt;p&gt;In &lt;a href="https://github.com/GetStream/encrypted-web-chat/blob/main/src/lib/setUser.js" rel="noopener noreferrer"&gt;&lt;code&gt;src/lib/setUser.js&lt;/code&gt;&lt;/a&gt;, we define the function that sets the chat client's user and updates it with the given key pair's public key. Sending the public key is necessary for other users to derive the key required for encrypting and decrypting communication with our user.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;In this function, we import the &lt;code&gt;chatClient&lt;/code&gt; defined in the previous step. It takes a user id and a &lt;strong&gt;key pair&lt;/strong&gt;, then it calls &lt;code&gt;chatClient.setUser&lt;/code&gt; to set the user. After that, it checks whether that user already has a public key and if it matches the public key in the key pair given. If the public key matches or is non-existent, we update that user with the given public key; if not, we disconnect and display an error.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sender Component
&lt;/h2&gt;

&lt;p&gt;In &lt;a href="https://github.com/GetStream/encrypted-web-chat/blob/main/src/components/Sender.js" rel="noopener noreferrer"&gt;&lt;code&gt;src/components/Sender.js&lt;/code&gt;&lt;/a&gt;, we define the first screen, where we choose our user id, and can generate a key pair using the function we described in &lt;code&gt;generateKey.js&lt;/code&gt;, or, if this is an existing user, paste the key pair generated at the time of user creation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2F9GOjC1T.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2F9GOjC1T.png" alt="Image shows a login form with an id field, a key pair field,  a generate button, and a submit button"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Recipient Component
&lt;/h2&gt;

&lt;p&gt;In &lt;a href="https://github.com/GetStream/encrypted-web-chat/blob/main/src/components/Recipient.js" rel="noopener noreferrer"&gt;&lt;code&gt;src/components/Recipient.js&lt;/code&gt;&lt;/a&gt;, we define the second screen, where we choose the id of the user with whom we want to communicate. The component will fetch this user with &lt;a href="https://getstream.io/chat/docs/query_users/?language=js" rel="noopener noreferrer"&gt;&lt;code&gt;chatClient.queryUsers&lt;/code&gt;&lt;/a&gt;. The result of that call will contain the user's public key, which we'll use to derive the encryption/decryption key.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2Fkz3o7cl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2Fkz3o7cl.png" alt="Image shows a form with a field for the user id you want to communicate with and a submit button"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  KeyDeriver Component
&lt;/h2&gt;

&lt;p&gt;In &lt;a href="https://github.com/GetStream/encrypted-web-chat/blob/main/src/components/KeyDeriver.js" rel="noopener noreferrer"&gt;&lt;code&gt;src/components/KeyDeriver.js&lt;/code&gt;&lt;/a&gt;, we define the third screen, where the key is derived using the method we implemented in &lt;code&gt;deriveKey.js&lt;/code&gt; with the sender's (us) private key and the recipient's public key. This component is merely a passive loading screen since the information needed was collected in the previous two screens. But it will show an error if there's an issue with the keys.&lt;/p&gt;

&lt;h2&gt;
  
  
  EncryptedMessage Component
&lt;/h2&gt;

&lt;p&gt;In &lt;a href="https://github.com/GetStream/encrypted-web-chat/blob/main/src/components/EncryptedMessage.js" rel="noopener noreferrer"&gt;&lt;code&gt;src/components/EncryptedMessage.js&lt;/code&gt;&lt;/a&gt;, we customize Stream Chat's Message component to decrypt the message using the method we defined in &lt;code&gt;decrypt.js&lt;/code&gt; alongside the encrypted data and the derived key.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FCmsBNLz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FCmsBNLz.png" alt="Image shows a chat message saying This is an encrypted message"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Without this customization of the Message component, it would show up like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FW2ifeXI.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FW2ifeXI.png" alt="Image shows a chat message with unintelligible text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The customization is done by wrapping Stream Chat's &lt;code&gt;MessageSimple&lt;/code&gt; component and using the &lt;code&gt;useEffect&lt;/code&gt; hook to modify the message prop with the decrypt method.&lt;/p&gt;

&lt;h2&gt;
  
  
  EncryptedMessageInput Component
&lt;/h2&gt;

&lt;p&gt;In &lt;a href="https://github.com/GetStream/encrypted-web-chat/blob/main/src/components/EncryptedMessageInput.js" rel="noopener noreferrer"&gt;&lt;code&gt;src/components/EncryptedMessageInput.js&lt;/code&gt;&lt;/a&gt;, we customize Stream Chat's MessageInput component to encrypt the message written before sending it using the method we defined in &lt;code&gt;encrypt.js&lt;/code&gt; alongside the original text.&lt;/p&gt;

&lt;p&gt;The customization is done by wrapping Stream Chat's &lt;code&gt;MessageInputLarge&lt;/code&gt; component and settings the &lt;code&gt;overrideSubmitHandler&lt;/code&gt; prop to a function that encrypts the text before sending to the channel.&lt;/p&gt;

&lt;h2&gt;
  
  
  Chat Component
&lt;/h2&gt;

&lt;p&gt;And finally, in &lt;a href="https://github.com/GetStream/encrypted-web-chat/blob/main/src/components/Chat.js" rel="noopener noreferrer"&gt;&lt;code&gt;src/components/Chat.js&lt;/code&gt;&lt;/a&gt;, we build the whole chat screen using Stream Chat's components and our custom Message and EncryptedMessageInput components.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;MessageList&lt;/code&gt; component has a &lt;code&gt;Message&lt;/code&gt; prop, set to the custom &lt;code&gt;EncryptedMessage&lt;/code&gt; component, and the &lt;code&gt;EncryptedMessageInput&lt;/code&gt; can just be placed right below it in the hierarchy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next Steps With Web Crypto API
&lt;/h2&gt;

&lt;p&gt;Congratulations! You just learned how to implement basic end-to-end encryption in your web apps. It's important to know this is the most basic form of end-to-end encryption. It lacks some additional tweaks that can make it more bullet-proof for the real world, such as &lt;a href="https://en.wikipedia.org/wiki/Padding_(cryptography)#Randomized_padding" rel="noopener noreferrer"&gt;randomized padding&lt;/a&gt;, &lt;a href="https://en.wikipedia.org/wiki/Digital_signature" rel="noopener noreferrer"&gt;digital signature&lt;/a&gt;, and &lt;a href="https://en.wikipedia.org/wiki/Forward_secrecy" rel="noopener noreferrer"&gt;forward secrecy&lt;/a&gt;, among others. Also, for real-world usage, it's vital to get the help of application security professionals.&lt;/p&gt;

&lt;p&gt;PS: Special thanks to Junxiao in the comments for correcting my mistakes :-)&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>beginners</category>
      <category>tutorial</category>
      <category>security</category>
    </item>
    <item>
      <title>Moderate Chat Content with Swift on AWS Lambda</title>
      <dc:creator>Matheus Cardoso</dc:creator>
      <pubDate>Fri, 02 Oct 2020 12:28:03 +0000</pubDate>
      <link>https://dev.to/cardoso/moderate-chat-content-with-swift-on-aws-lambda-je9</link>
      <guid>https://dev.to/cardoso/moderate-chat-content-with-swift-on-aws-lambda-je9</guid>
      <description>&lt;p&gt;Most of the time, when building a chat application, it's essential to have some level of control over what your users can share and say to each other.&lt;/p&gt;

&lt;p&gt;In this tutorial, we'll use &lt;a href="https://github.com/getstream/swift-lambda" rel="noopener noreferrer"&gt;Swift Lambda&lt;/a&gt; and &lt;a href="https://getstream.io/chat/" rel="noopener noreferrer"&gt;Stream's powerful chat API&lt;/a&gt; to build a content moderation system that can prevent users from sending unwanted content. In this case, we'll filter out possible credit card data to prevent our users from sharing it with scammers. However, you can adapt it to other sensitive data or to block bad words.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FKgssyhZ.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FKgssyhZ.gif" alt="Animation shows a chat screen with a message containing credit card information being typed and then redacted after submission"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can find the completed project on GitHub in the &lt;a href="https://github.com/GetStream/swift-lambda/tree/main/Samples" rel="noopener noreferrer"&gt;Samples folder inside the Swift Lambda repository&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://getstream.io/blog/inapp-support-chat-ios/" rel="noopener noreferrer"&gt;Set up a Chat Application&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://getstream.io/blog/swift-lambda-aws-serverless/" rel="noopener noreferrer"&gt;Set up Swift Lambda&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Set the Presend Webhook URL
&lt;/h2&gt;

&lt;p&gt;After you've built your iOS chat app and the Swift Lambda is up and running, you need to configure the Presend Webhook URL using the &lt;a href="https://getstream.io/chat/docs_rest/#update-application" rel="noopener noreferrer"&gt;Stream Chat REST API&lt;/a&gt;. To do this, you'll need your API Key, a server-side JWT, and your AWS Lambda URL.&lt;/p&gt;

&lt;p&gt;To get the API Key, go to the Stream Chat dashboard. It will be there, similar to the image below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2Fgp7Yslh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2Fgp7Yslh.png" alt="Image shows a Stream application with the API Key and Secret in the Stream Dashboard"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also, copy the secret, as it is needed to generate the server-side JWT. You can use &lt;a href="https://jwt.io/" rel="noopener noreferrer"&gt;jwt.io&lt;/a&gt; to generate it. Just paste the secret inside the text field on the right side and copy the JWT on the left side.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2F5wFDu5h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2F5wFDu5h.png" alt="Image shows JWT.io website with arrows pointing to the generated JWT and the text field where the secret is pasted"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, to set the Presend Webhook URL, you can run the curl command below in the terminal. Make sure to replace &lt;code&gt;[api_key]&lt;/code&gt;, &lt;code&gt;[jwt]&lt;/code&gt;, and &lt;code&gt;[aws_lambda_endpoint_url]&lt;/code&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  Configure Swift Lambda
&lt;/h2&gt;

&lt;p&gt;At first, your Swift Lambda will handle &lt;code&gt;GET&lt;/code&gt; requests. Change it to process &lt;code&gt;POST&lt;/code&gt; requests instead, which can be done by editing the &lt;code&gt;serverless.yml&lt;/code&gt; file and swapping the line &lt;code&gt;method: get&lt;/code&gt; with &lt;code&gt;method: post&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Filter out credit card numbers
&lt;/h2&gt;

&lt;p&gt;Now that the Swift Lambda is configured, we can get to the code part.&lt;/p&gt;

&lt;p&gt;First, we need a function to redact credit card numbers from a message by replacing the numbers with asterisks. The code below does just that by using regular expressions to match valid numbers of known credit card operators.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;You should add that to the &lt;code&gt;main.swift&lt;/code&gt; file.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handle the message
&lt;/h2&gt;

&lt;p&gt;When the &lt;code&gt;POST&lt;/code&gt; request hits your lambda, it will contain a JSON object describing the new message. To see which fields you can expect in this payload, see the &lt;a href="https://getstream.io/chat/docs/presend_message_hook/?language=js" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;main.swift&lt;/code&gt; file, paste the code below.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;That code will parse the JSON body into a dictionary and modify the message object by running its "text" field through the credit card redaction function. As specified in the documentation, we return this modified message object to submit the redacted version.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploying and testing the content moderation
&lt;/h2&gt;

&lt;p&gt;The main advantage of using &lt;a href="https://github.com/GetStream/swift-lambda" rel="noopener noreferrer"&gt;Swift Lambda&lt;/a&gt; is that it's possible to iterate fast with it. After writing the moderation code, just run the &lt;code&gt;./Scripts/deploy.sh&lt;/code&gt; script again and wait a few seconds.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FJO0nsi2.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FJO0nsi2.gif" alt="This animation shows the deploy script running and finishing successfully"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After the upload is finished, you can run the chat app and type something in any channel. If it contains a seemingly valid credit card number such as &lt;code&gt;6011881485017922&lt;/code&gt;, it should be replaced with asterisks.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2F0fnxECF.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2F0fnxECF.png" alt="Image shows a chat UI running on iPhone simulator with a chat screen containing redacted messages"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Next steps with Swift Lambda
&lt;/h2&gt;

&lt;p&gt;Congratulations! You've just uploaded a real Swift backend to AWS. This moderation code is simple and made to demonstrate a usage of Swift Lambda to empower your chat apps. There are many ways to build even richer use cases with Swift Lambda. To find out more, check out the &lt;a href="https://getstream.io/blog/swift-lambda-chat-bot/" rel="noopener noreferrer"&gt;chatbot tutorial with Swift Lambda&lt;/a&gt; and &lt;a href="https://getstream.io/chat/docs/?language=swift" rel="noopener noreferrer"&gt;Stream Chat's documentation&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ios</category>
      <category>swift</category>
      <category>aws</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
