<?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: Anna Skokova</title>
    <description>The latest articles on DEV Community by Anna Skokova (@anna_skokova_9ca00a251bad).</description>
    <link>https://dev.to/anna_skokova_9ca00a251bad</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4234757%2F2d84399d-ee9d-48ca-9139-34c63b836183.png</url>
      <title>DEV Community: Anna Skokova</title>
      <link>https://dev.to/anna_skokova_9ca00a251bad</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/anna_skokova_9ca00a251bad"/>
    <language>en</language>
    <item>
      <title>How to build and publish an iOS app from Windows (without buying a Mac)</title>
      <dc:creator>Anna Skokova</dc:creator>
      <pubDate>Tue, 10 Nov 2026 10:47:02 +0000</pubDate>
      <link>https://dev.to/anna_skokova_9ca00a251bad/how-to-build-and-publish-an-ios-app-from-windows-without-buying-a-mac-3hho</link>
      <guid>https://dev.to/anna_skokova_9ca00a251bad/how-to-build-and-publish-an-ios-app-from-windows-without-buying-a-mac-3hho</guid>
      <description>&lt;p&gt;You've built your app. Maybe it's Flutter or React Native and the Android version is already on Google Play. Maybe it's a small Swift project you wrote in VS Code. Then you hit the wall every Windows developer hits sooner or later:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Xcode only runs on macOS.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You need Xcode (or at least Apple's build tools) to compile an iOS app, sign it and upload it to App Store Connect. There's no official Windows version, and there isn't going to be one.&lt;/p&gt;

&lt;p&gt;So what are your options if you don't own a Mac? Here's an honest overview, followed by a full walkthrough of the approach I use.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Disclosure:&lt;/strong&gt; I build &lt;a href="https://justmac.app/" rel="noopener noreferrer"&gt;JustMac&lt;/a&gt;, one of the services mentioned below. I've tried to describe every option fairly, including the ones that are free.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Option 1: Let a CI service build it for you
&lt;/h2&gt;

&lt;p&gt;If your project is Flutter or React Native, you may not need a Mac desktop at all:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Expo EAS Build&lt;/strong&gt; builds iOS apps in the cloud for Expo / React Native projects, and &lt;strong&gt;EAS Submit&lt;/strong&gt; can upload the result to App Store Connect.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Codemagic&lt;/strong&gt; does the same for Flutter (and other frameworks).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Actions&lt;/strong&gt; has macOS runners. They're free for public repositories and billed per minute for private ones.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Good for:&lt;/strong&gt; repeatable builds once everything works.&lt;br&gt;
&lt;strong&gt;Not great for:&lt;/strong&gt; the first setup. When signing fails, a CocoaPods dependency breaks or you need to see your app in the iOS Simulator, debugging through CI logs is slow and painful.&lt;/p&gt;
&lt;h2&gt;
  
  
  Option 2: Buy a (used) Mac mini
&lt;/h2&gt;

&lt;p&gt;A second-hand Apple silicon Mac mini is the most capable long-term option. If you'll ship iOS apps every week, it's probably worth it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Good for:&lt;/strong&gt; daily iOS development.&lt;br&gt;
&lt;strong&gt;Not great for:&lt;/strong&gt; "I need to ship one build this week." It's an upfront cost, and you need a desk, a screen and time to set it up.&lt;/p&gt;
&lt;h2&gt;
  
  
  Option 3: Rent a remote Mac
&lt;/h2&gt;

&lt;p&gt;You rent a real Mac in a data centre and use its desktop remotely. There are several providers: MacinCloud, MacStadium, AWS EC2 Mac instances, and smaller services like JustMac (mine). They differ mainly in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;How you connect:&lt;/strong&gt; a VNC / remote desktop client, or simply a browser tab.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Minimum rental period:&lt;/strong&gt; Apple's macOS licence requires a minimum lease of 24 hours, so you'll usually see daily, weekly or monthly plans.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dedicated or shared:&lt;/strong&gt; a whole physical Mac versus a user account on a shared machine.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Good for:&lt;/strong&gt; occasional builds, first setup, debugging signing problems, testing in the Simulator.&lt;br&gt;
&lt;strong&gt;Not great for:&lt;/strong&gt; heavy daily use, where buying becomes cheaper.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ What about a "Hackintosh" or a macOS virtual machine on your PC? Apple's licence only allows macOS on Apple hardware, and these setups break regularly with Xcode updates. I wouldn't build anything you plan to publish on them.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Walkthrough: from Windows to TestFlight with a rented Mac
&lt;/h2&gt;

&lt;p&gt;Here's the full process. I'll use JustMac in the screenshots, but the steps on the Mac are the same on any remote Mac, or on a Mac you own.&lt;/p&gt;
&lt;h3&gt;
  
  
  What you need first
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;An &lt;strong&gt;Apple Account&lt;/strong&gt; (free).&lt;/li&gt;
&lt;li&gt;An &lt;strong&gt;Apple Developer Program&lt;/strong&gt; membership (US$99/year). You don't need it to run your app in the Simulator, but you do need it to upload to TestFlight or the App Store.&lt;/li&gt;
&lt;li&gt;Your project in a &lt;strong&gt;Git repository&lt;/strong&gt;, or as an archive you can upload.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Step 1: Get a Mac and open it
&lt;/h3&gt;

&lt;p&gt;Pick a machine, pay for a day, and open the desktop. With JustMac it opens in a browser tab, so there's nothing to install on Windows.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjvk7vk2i6ltc9qtpf8xz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjvk7vk2i6ltc9qtpf8xz.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 2: Install Xcode
&lt;/h3&gt;

&lt;p&gt;Open the &lt;strong&gt;App Store&lt;/strong&gt; on the Mac, sign in with your own Apple Account and install &lt;strong&gt;Xcode&lt;/strong&gt;. It's a big download, so start this first and grab a coffee.&lt;/p&gt;

&lt;p&gt;Then open Xcode once and let it install its additional components (including the iOS Simulator runtime).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy27zzqwjdermon27zhen.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy27zzqwjdermon27zhen.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 3: Bring your project over
&lt;/h3&gt;

&lt;p&gt;The easiest way is Git. Open &lt;strong&gt;Terminal&lt;/strong&gt; and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/you/your-app.git
&lt;span class="nb"&gt;cd&lt;/span&gt; your-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No Git repository? Upload an archive instead. In JustMac you can drag a file onto the Mac window.&lt;/p&gt;

&lt;p&gt;For &lt;strong&gt;Flutter&lt;/strong&gt;, install the toolchain with Homebrew first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/bin/bash -c &lt;span class="s2"&gt;"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"&lt;/span&gt;
brew install --cask flutter
brew install cocoapods
flutter pub get
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For &lt;strong&gt;React Native&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew install node cocoapods
npm install
&lt;span class="nb"&gt;cd&lt;/span&gt; ios &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; pod install &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd&lt;/span&gt; ..
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4: Run it in the Simulator
&lt;/h3&gt;

&lt;p&gt;Before worrying about signing, make sure the app actually builds and runs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Native Swift:&lt;/strong&gt; open the &lt;code&gt;.xcodeproj&lt;/code&gt; / &lt;code&gt;.xcworkspace&lt;/code&gt;. In the toolbar at the top of Xcode, click the device name next to your app's name and pick an iPhone from the &lt;strong&gt;iOS Simulators&lt;/strong&gt; section. Then press &lt;strong&gt;Run&lt;/strong&gt; (⌘R).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flutter:&lt;/strong&gt; &lt;code&gt;open -a Simulator&lt;/code&gt;, then &lt;code&gt;flutter run&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;React Native:&lt;/strong&gt; &lt;code&gt;npx react-native run-ios&lt;/code&gt; (or &lt;code&gt;npx expo run:ios&lt;/code&gt; with Expo).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fiwywlelw096wsfplehb4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fiwywlelw096wsfplehb4.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is where most "it works on Android" projects find their iOS-only problems: missing permissions in &lt;code&gt;Info.plist&lt;/code&gt;, CocoaPods version conflicts, or a minimum iOS version that's too low for a dependency. Fix them now, while you can see what's happening.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: Set up signing
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;In Xcode, go to &lt;strong&gt;Settings → Accounts&lt;/strong&gt; and add your Apple Account.&lt;/li&gt;
&lt;li&gt;Select your project, then the app target, then the &lt;strong&gt;Signing &amp;amp; Capabilities&lt;/strong&gt; tab.&lt;/li&gt;
&lt;li&gt;Tick &lt;strong&gt;Automatically manage signing&lt;/strong&gt; and choose your &lt;strong&gt;Team&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Make sure the &lt;strong&gt;Bundle Identifier&lt;/strong&gt; is unique (for example &lt;code&gt;com.yourname.yourapp&lt;/code&gt;).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Xcode creates the certificate and provisioning profile for you.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fykm6bgzvcridendvp65d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fykm6bgzvcridendvp65d.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 6: Create the app in App Store Connect
&lt;/h3&gt;

&lt;p&gt;In a browser, open &lt;a href="https://appstoreconnect.apple.com" rel="noopener noreferrer"&gt;App Store Connect&lt;/a&gt;, go to &lt;strong&gt;Apps → + → New App&lt;/strong&gt;, and choose the same Bundle ID you used in Xcode. You only do this once per app.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 7: Archive and upload
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Look at the toolbar at the top of the Xcode window. In the middle you'll see your app's name followed by a device, for example &lt;strong&gt;MyApp › iPhone 16&lt;/strong&gt;. Click the device name (&lt;strong&gt;iPhone 16&lt;/strong&gt;) and choose &lt;strong&gt;Any iOS Device (arm64)&lt;/strong&gt; from the list. This tells Xcode to build for real iPhones instead of the Simulator.&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Product → Archive&lt;/strong&gt;. (If &lt;strong&gt;Archive&lt;/strong&gt; is greyed out, a simulator is still selected: go back to step 1.)&lt;/li&gt;
&lt;li&gt;When the Organizer window opens, select the archive and click &lt;strong&gt;Distribute App → App Store Connect → Upload&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For Flutter you can build the archive from the terminal with &lt;code&gt;flutter build ipa&lt;/code&gt;, then upload it from the Organizer or with Apple's &lt;strong&gt;Transporter&lt;/strong&gt; app.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9nnh44s1mohalx9ipjna.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9nnh44s1mohalx9ipjna.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 8: TestFlight and review
&lt;/h3&gt;

&lt;p&gt;After a few minutes of processing, the build appears in App Store Connect under &lt;strong&gt;TestFlight&lt;/strong&gt;. Add yourself as a tester, install the &lt;strong&gt;TestFlight&lt;/strong&gt; app on an iPhone and try the real thing. When you're happy, attach the build to a version and submit it for App Store review.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fr8f9cnnp445qqbpdsec7.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fr8f9cnnp445qqbpdsec7.PNG" alt=" " width="800" height="1738"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Before your rental ends
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Push your code&lt;/strong&gt; (including any changes Xcode made to project files) back to Git.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sign out&lt;/strong&gt; of your Apple Account in Xcode and the App Store if you want to be extra careful. On JustMac the Mac is wiped to factory settings an hour after the rental ends anyway.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Which option should you choose?
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Situation&lt;/th&gt;
&lt;th&gt;Best option&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Expo / React Native project that already builds&lt;/td&gt;
&lt;td&gt;Expo EAS Build&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Flutter project, builds already work&lt;/td&gt;
&lt;td&gt;Codemagic or GitHub Actions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;First iOS build, signing problems, need the Simulator&lt;/td&gt;
&lt;td&gt;Rent a Mac for a day or a week&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You'll do iOS development every week&lt;/td&gt;
&lt;td&gt;Buy a Mac mini&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;My personal rule: &lt;strong&gt;rent first, automate later.&lt;/strong&gt; Getting the first build through signing and App Store Connect is much easier when you can see a real Xcode window. Once it works, moving the build to CI is straightforward.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;If you want to try the browser-based approach, &lt;a href="https://justmac.app/xcode-on-windows" rel="noopener noreferrer"&gt;JustMac&lt;/a&gt; rents dedicated Mac minis and MacBook Airs by the day, week or month, and the desktop opens in a browser tab. Questions about any of the steps above? Ask in the comments and I'll help.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ios</category>
      <category>xcode</category>
      <category>windows</category>
      <category>mobile</category>
    </item>
  </channel>
</rss>
