<?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>Forem: Amir</title>
    <description>The latest articles on Forem by Amir (@samadipour).</description>
    <link>https://forem.com/samadipour</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%2F415435%2Fc75e19a4-ca53-48e4-8874-ba68d4216d26.jpeg</url>
      <title>Forem: Amir</title>
      <link>https://forem.com/samadipour</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/samadipour"/>
    <language>en</language>
    <item>
      <title>MacOS Tips &amp; Tricks</title>
      <dc:creator>Amir</dc:creator>
      <pubDate>Sun, 13 Nov 2022 15:14:04 +0000</pubDate>
      <link>https://forem.com/samadipour/macos-tips-tricks-25nb</link>
      <guid>https://forem.com/samadipour/macos-tips-tricks-25nb</guid>
      <description>&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Charge Limiter&lt;/li&gt;
&lt;li&gt;Microsoft AutoUpdate&lt;/li&gt;
&lt;li&gt;Dock&lt;/li&gt;
&lt;li&gt;Menu Bar&lt;/li&gt;
&lt;li&gt;Brew&lt;/li&gt;
&lt;li&gt;Updating everything Automatically&lt;/li&gt;
&lt;li&gt;Useful Application&lt;/li&gt;
&lt;li&gt;ZSH&lt;/li&gt;
&lt;li&gt;Shortcuts&lt;/li&gt;
&lt;li&gt;The Power of Option key&lt;/li&gt;
&lt;li&gt;Common errors&lt;/li&gt;
&lt;li&gt;General Tips&lt;/li&gt;
&lt;li&gt;Useful Sites&lt;/li&gt;
&lt;li&gt;Other Resources&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Charge Limiter
&lt;/h2&gt;

&lt;p&gt;You can use one of these to limit how much your MacBook charges:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/davidwernhart/AlDente-Charge-Limiter" rel="noopener noreferrer"&gt;AlDente&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/actuallymentor/battery" rel="noopener noreferrer"&gt;Battery (CLI)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Make sure you read the readme file and know what you are doing. In most cases, you don't need this but if you are a pro user, you might like controlling it yourself.&lt;/p&gt;




&lt;h2&gt;
  
  
  Microsoft AutoUpdate
&lt;/h2&gt;

&lt;p&gt;Disable opening popup every day (&lt;a href="https://superuser.com/questions/1544338/turn-off-microsoft-apps-auto-update-on-a-mac" rel="noopener noreferrer"&gt;source&lt;/a&gt;)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;plutil &lt;span class="nt"&gt;-replace&lt;/span&gt; StartInterval &lt;span class="nt"&gt;-integer&lt;/span&gt; 864000 /Library/LaunchAgents/com.microsoft.update.agent.plist
&lt;span class="nb"&gt;sudo &lt;/span&gt;plutil &lt;span class="nt"&gt;-replace&lt;/span&gt; RunAtLoad &lt;span class="nt"&gt;-bool&lt;/span&gt; no /Library/LaunchAgents/com.microsoft.update.agent.plist
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check for update manually (&lt;a href="https://docs.microsoft.com/en-us/deployoffice/mac/update-office-for-mac-using-msupdate" rel="noopener noreferrer"&gt;source&lt;/a&gt;)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/Library/Application&lt;span class="se"&gt;\ &lt;/span&gt;Support/Microsoft/MAU2.0/Microsoft&lt;span class="se"&gt;\ &lt;/span&gt;AutoUpdate.app/Contents/MacOS/msupdate &lt;span class="nt"&gt;-l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open GUI manually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/Library/Application&lt;span class="se"&gt;\ &lt;/span&gt;Support/Microsoft/MAU2.0/Microsoft AutoUpdate.app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Dock
&lt;/h2&gt;

&lt;p&gt;Location of the setting file: &lt;code&gt;/Users/[user-name]/Library/Preference/com.apple.Dock&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Parameters description: &lt;a href="https://developer.apple.com/documentation/devicemanagement/dock" rel="noopener noreferrer"&gt;https://developer.apple.com/documentation/devicemanagement/dock&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lock size of the dock&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;defaults write com.apple.dock size-immutable &lt;span class="nt"&gt;-bool&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; killall Dock
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lock position of the dock&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;defaults write com.apple.dock position-immutable &lt;span class="nt"&gt;-bool&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; killall Dock
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add empty item&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;defaults write com.apple.dock persistent-apps &lt;span class="nt"&gt;-array-add&lt;/span&gt; &lt;span class="s1"&gt;'{"tile-type"="spacer-tile";}'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; killall Dock
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Revert to default&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;defaults delete com.apple.dock&lt;span class="p"&gt;;&lt;/span&gt; killall Dock
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Menu Bar
&lt;/h2&gt;

&lt;p&gt;In order to make it visible even in the fullscreen mode, you can go to &lt;code&gt;System Preferences &amp;gt; Dock and Menu Bar&lt;/code&gt; and uncheck &lt;code&gt;Automatically hide and show the menu bar in full screen&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You can also set it individually for each app: (true means it will show it all the time in the fullscreen mode)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;defaults&lt;/span&gt; &lt;span class="nx"&gt;write&lt;/span&gt; &lt;span class="nx"&gt;com&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;example&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SomeApp&lt;/span&gt; &lt;span class="nx"&gt;AppleMenuBarVisibleInFullscreen&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;bool&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;💡 If you don’t know the app bundle identifier name, follow the first general tip.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Brew
&lt;/h2&gt;

&lt;p&gt;Get the list of installed packages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew leaves
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Packages that I like to install:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cocoapods
composer
ffmpeg
gh
jq
openjdk
php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Updating everything Automatically
&lt;/h2&gt;

&lt;p&gt;Brew&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; brew upgrade &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; brew upgrade &lt;span class="nt"&gt;--cask&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Python packages (without package manager)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 &lt;span class="nt"&gt;-m&lt;/span&gt; pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-U&lt;/span&gt; pip
pip3 list &lt;span class="nt"&gt;--outdated&lt;/span&gt; &lt;span class="nt"&gt;--format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;json | jq &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'.[] | "\(.name)==\(.latest_version)"'&lt;/span&gt; | xargs &lt;span class="nt"&gt;-n1&lt;/span&gt; pip3 &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-U&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check system updates&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;softwareupdate &lt;span class="nt"&gt;-l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;AppStore installed apps&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;mas &lt;span class="c"&gt;# install&lt;/span&gt;
mas outdated &lt;span class="c"&gt;# show all the packages that need update&lt;/span&gt;
mas upgrade &lt;span class="c"&gt;# update all of them&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Useful Application
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Free/OpenSource:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://shottr.cc/" rel="noopener noreferrer"&gt;Shottr&lt;/a&gt; → Screenshot / OCR / Scrolling Screenshot&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://alt-tab-macos.netlify.app/" rel="noopener noreferrer"&gt;AltTab&lt;/a&gt; → Window switcher with previews&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/p0deje/Maccy" rel="noopener noreferrer"&gt;Maccy&lt;/a&gt; → Clipboard manager&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://iterm2.com/" rel="noopener noreferrer"&gt;iTerm2&lt;/a&gt; → Terminal emulator&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/ddddxxx/LyricsX" rel="noopener noreferrer"&gt;LyricsX&lt;/a&gt; → Lyrics overly&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://handbrake.fr/" rel="noopener noreferrer"&gt;HandBrake&lt;/a&gt; → Compress and convert video&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://freemacsoft.net/appcleaner/" rel="noopener noreferrer"&gt;AppCleaner&lt;/a&gt; → Uninstall apps&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://apps.apple.com/us/app/amphetamine/id937984704" rel="noopener noreferrer"&gt;Amphetamine&lt;/a&gt; → Energy saver settings&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://karabiner-elements.pqrs.org/" rel="noopener noreferrer"&gt;Karabiner-Elements&lt;/a&gt; -&amp;gt; A powerful keyboard customizer&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/koekeishiya/yabai" rel="noopener noreferrer"&gt;Yabai&lt;/a&gt; -&amp;gt; Tiling window management&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/MonitorControl/MonitorControl" rel="noopener noreferrer"&gt;MonitorControl&lt;/a&gt; -&amp;gt; Control external display's brightness &amp;amp; volume&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://mos.caldis.me/" rel="noopener noreferrer"&gt;MOS&lt;/a&gt; -&amp;gt; Smooth scrolling and set scroll direction&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.raycast.com/" rel="noopener noreferrer"&gt;Raycast&lt;/a&gt; -&amp;gt; Better Spotlight&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://imageoptim.com/mac" rel="noopener noreferrer"&gt;ImageOptim&lt;/a&gt; -&amp;gt; Reduces image file sizes&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dbngin.com/" rel="noopener noreferrer"&gt;DBngin&lt;/a&gt; -&amp;gt; Database Version Management Tool&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://tableplus.com/" rel="noopener noreferrer"&gt;TablePlus&lt;/a&gt; -&amp;gt; Database management&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;CLI:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/mas-cli/mas" rel="noopener noreferrer"&gt;mas&lt;/a&gt; -&amp;gt; Mac App Store command line interface&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/yt-dlp/yt-dlp" rel="noopener noreferrer"&gt;YT-DLP&lt;/a&gt; -&amp;gt; Download video/audio from youtube&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Paid:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://folivora.ai/" rel="noopener noreferrer"&gt;BetterTouchTool&lt;/a&gt; -&amp;gt; Customize various input devices&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.macbartender.com/" rel="noopener noreferrer"&gt;Bartender&lt;/a&gt; -&amp;gt; Control and customize menu bar&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://rogueamoeba.com/soundsource/" rel="noopener noreferrer"&gt;Sound Source&lt;/a&gt; -&amp;gt; Sound control for apps and 3rd party monitors&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.corecode.io/macupdater/" rel="noopener noreferrer"&gt;MacUpdater&lt;/a&gt; -&amp;gt; Automatically track the latest updates of all applications installed&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://movistprime.com/" rel="noopener noreferrer"&gt;Movist&lt;/a&gt; -&amp;gt; Better video player&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ZSH
&lt;/h2&gt;

&lt;p&gt;Oh My ZSH install&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Configuration&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;ZSH_THEME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"robbyrussell"&lt;/span&gt;
&lt;span class="nv"&gt;DISABLE_UPDATE_PROMPT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"true"&lt;/span&gt;
&lt;span class="nv"&gt;HIST_STAMPS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"yyyy/mm/dd"&lt;/span&gt;

&lt;span class="nv"&gt;plugins&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;git extract zsh-autosuggestions&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Useful Plugins (&lt;a href="https://github.com/ohmyzsh/ohmyzsh/wiki/Plugins" rel="noopener noreferrer"&gt;all&lt;/a&gt;)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# zsh-autosuggestions&lt;/span&gt;
git clone https://github.com/zsh-users/zsh-autosuggestions &lt;span class="nv"&gt;$ZSH_CUSTOM&lt;/span&gt;/plugins/zsh-autosuggestions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Shortcuts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Change volume in small increments: &lt;code&gt;Shift ⇧ + Option ⌥ (alt) + Volume Up/Down&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Change brightness in small increments: &lt;code&gt;Shift ⇧ + Option ⌥ (alt) + Brightness Up/Down&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Entering/Exiting fullscreen mode: &lt;code&gt;fn + F&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Paste without formatting: &lt;code&gt;Command ⌘ + Option ⌥ (alt) + Shift ⇧ + V&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Permanent deleting a file: &lt;code&gt;Command ⌘ + Option ⌥ (alt) + Backspace&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Show hidden files in Finder: &lt;code&gt;Command ⌘ + Shift ⇧ + .&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Power of Option key
&lt;/h2&gt;

&lt;p&gt;Do all of these when holding the &lt;code&gt;Option&lt;/code&gt; key!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hit the volume icon to see both input and output&lt;/li&gt;
&lt;li&gt;Hit wifi icon to see every little detail&lt;/li&gt;
&lt;li&gt;Hit menu bar items to see other options&lt;/li&gt;
&lt;li&gt;Hit close window to close all instances of that application&lt;/li&gt;
&lt;li&gt;Right click after you copied something to show &lt;code&gt;Move item here&lt;/code&gt; instead of paste.&lt;/li&gt;
&lt;li&gt;When seeing an image, Click on &lt;code&gt;File &amp;gt; Save As&lt;/code&gt; while holding the option to convert your image to other formats. When selecting a format, hold the option to see more formats!&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Common errors
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;App is damaged and can’t be opened. You should move it to the Trash.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;xattr &lt;span class="nt"&gt;-c&lt;/span&gt; /Applications/[name].app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  General Tips
&lt;/h2&gt;

&lt;p&gt;1- &lt;strong&gt;Finding app bundle identifier:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;osascript&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id of app "TextEdit"&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2- &lt;strong&gt;Three-finger drag:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Go to &lt;code&gt;System Preferences &amp;gt; Accessibility &amp;gt; Pointer Control &amp;gt; Trackpad options&lt;/code&gt; and then enable dragging with  &lt;code&gt;three finger drag&lt;/code&gt;. Now you can drag any window with three fingers.&lt;/p&gt;

&lt;p&gt;3- &lt;strong&gt;Change drag &amp;amp; drop speed:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Go to &lt;code&gt;System Preference &amp;gt; Accessibility &amp;gt; Pointer Control&lt;/code&gt; and change &lt;code&gt;Spring-loading delay&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Useful Sites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://macosicons.com/#/" rel="noopener noreferrer"&gt;App Icons&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.applegamingwiki.com/wiki/Home" rel="noopener noreferrer"&gt;Compatibility of every game on M1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/PlayCover/PlayCover" rel="noopener noreferrer"&gt;Sideload iOS apps on macOS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://doesitarm.com/" rel="noopener noreferrer"&gt;M1 supported application list&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Other Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://macos-defaults.com/" rel="noopener noreferrer"&gt;Defaults Commands&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/jaywcjlove/awesome-mac" rel="noopener noreferrer"&gt;MacOS Awesome&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fourth-wall.co.uk/post/my-16-favourite-finder-tips-for-mac" rel="noopener noreferrer"&gt;Finder Tips&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Jesse Skelto's Karabiner and Yabai tutorials

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=uaJSjgVEhMQ" rel="noopener noreferrer"&gt;Karabiner| Part 1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=PBPS2D9AKtI" rel="noopener noreferrer"&gt;Karabiner| Part 2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=JL1lz77YbUE" rel="noopener noreferrer"&gt;Yabai&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;a href="https://gist.github.com/devnoname120/4767a0aa18879217170fd0c68809fc24" rel="noopener noreferrer"&gt;devnoname120's macOS setup&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href="https://github.com/nnja/new-computer" rel="noopener noreferrer"&gt;nnja's new computer&lt;/a&gt;&lt;/li&gt;

&lt;/ul&gt;

</description>
      <category>macos</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Flutter: Automate iOS deployment and versioning</title>
      <dc:creator>Amir</dc:creator>
      <pubDate>Mon, 06 Jun 2022 09:42:49 +0000</pubDate>
      <link>https://forem.com/samadipour/flutter-automate-ios-deployment-5ghc</link>
      <guid>https://forem.com/samadipour/flutter-automate-ios-deployment-5ghc</guid>
      <description>&lt;p&gt;Deploying for iOS is typically a tedious and time-consuming task. You have to open the Xcode, change the version name and number, get an archive, press a bunch of buttons, wait for each step and finally hit upload.&lt;br&gt;
Today, we'll use Python to automate this process.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: This tutorial is for Flutter 3+, and I'm automating it with Python 3. I also worked on a bash version, but it's incomplete. You can get the entire script and bash version from &lt;a href="https://gist.github.com/SamadiPour/34126da2c8bae567b3b0dd8a83bc8b66" rel="noopener noreferrer"&gt;this gist&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&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%2Fuploads%2Farticles%2Fsxknq22xavz3y5kapyu2.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%2Fuploads%2Farticles%2Fsxknq22xavz3y5kapyu2.png" alt="Image description"&gt;&lt;/a&gt; &lt;/p&gt;
&lt;h2&gt;
  
  
  3rd Party tools
&lt;/h2&gt;

&lt;p&gt;There are a lot of articles and tools like &lt;a href="https://fastlane.tools/" rel="noopener noreferrer"&gt;Fastlane&lt;/a&gt; or &lt;a href="https://docs.codemagic.io/cli/codemagic-cli-tools/" rel="noopener noreferrer"&gt;Codemagic Cli&lt;/a&gt; that can help you to automate this process.&lt;br&gt;
We are not going to use them in this tutorial. We do it ourselves, which will give us more flexibility in the long run.&lt;/p&gt;



&lt;p&gt;In some projects, devs always release from the main branch, and it's easy to have the latest version number in the &lt;code&gt;pubspec.yaml&lt;/code&gt; file and keep it update.&lt;br&gt;
In other projects, you have to send a TestFlight version from different feature branches, and each time you want to deploy a new version, you must check AppStore Connect to see what the most recent version is.&lt;/p&gt;

&lt;p&gt;Step 2 to 4 is about automating this problem. In these sections, we will request to get the latest available version from the Apple server and ask the developer what version they want to set.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 1: Configure Xcode
&lt;/h2&gt;

&lt;p&gt;Before automating this process, we must make sure that we can build our app manually and project settings are correct. I will not include these steps in this tutorial because &lt;a href="https://docs.flutter.dev/deployment/ios" rel="noopener noreferrer"&gt;flutter documentation&lt;/a&gt; explained it very well.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 2: Get the API Key from Apple
&lt;/h2&gt;

&lt;p&gt;To get the latest version from Apple's server, we can use &lt;a href="https://developer.apple.com/documentation/appstoreconnectapi" rel="noopener noreferrer"&gt;App Store Connect API&lt;/a&gt;. But before we can use this API, We must first request to get access to API Key from &lt;a href="https://appstoreconnect.apple.com/access/api" rel="noopener noreferrer"&gt;Users and Access &amp;gt; Keys &amp;gt; App Store Connect API&lt;/a&gt;. This action is only available to the Account Holder role.&lt;br&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%2Fuploads%2Farticles%2F6vp4el69if3tgsqphvku.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%2Fuploads%2Farticles%2F6vp4el69if3tgsqphvku.png" alt="App Store Connect API page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After requesting access, you need to generate a new API Key.&lt;br&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%2Fuploads%2Farticles%2Fxxlvxtmm6s2a22iwe264.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%2Fuploads%2Farticles%2Fxxlvxtmm6s2a22iwe264.png" alt="Generate new API dialogue"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hit the (+) button, Enter a name and choose the access. In the access field, make sure to select the &lt;code&gt;Developer&lt;/code&gt; role because it has the ability to upload IPA files to the Apple Store.&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%2Fuploads%2Farticles%2Ftw4ah5wvmz2ghix9x6g5.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%2Fuploads%2Farticles%2Ftw4ah5wvmz2ghix9x6g5.png" alt="Generated API Key"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After generating API Key, you can see it in the Active section. Click on &lt;code&gt;Download API Key&lt;/code&gt; to get the .p8 file.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 3: Create JWT
&lt;/h2&gt;

&lt;p&gt;After obtaining all required credentials, it is time to generate a JWT token for use with the Apple Store Connect API.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: You can find your App ID from the URL when opening the app page.&lt;br&gt;
For example, In appstoreconnect.apple.com/apps/1555XXXXX, 1555XXXXX is your App ID&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To begin, declare credentials in the code as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;ISSUER_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;9f4xxxx-xxxx-xxxx-xxxx-xxxxxxxxx&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="n"&gt;KEY_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;2F9XXXXXXX&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="n"&gt;PRIVATE_KEY_PATH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;./private_keys/AuthKey_2F9XXXXXXX.p8&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="n"&gt;APP_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;1500000000&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this information, we can now construct JWT as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;EXP_IN_SEC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;

&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PRIVATE_KEY_PATH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;r+b&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;private_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;expiration_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tz&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;timezone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;utc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;timedelta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seconds&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;EXP_IN_SEC&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;encoded_jwt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;jwt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;iss&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ISSUER_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;exp&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;expiration_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;aud&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;appstoreconnect-v1&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;private_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;algorithm&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ES256&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;alg&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ES256&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;kid&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;KEY_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;typ&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;JWT&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note: In this section, we use a library to generate JWT, which must be installed as follows: 'pip install pyjwt'&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Step 4: Get the last version
&lt;/h2&gt;

&lt;p&gt;Now we can use the JWT we generated earlier to get the most recent TestFlight build.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;BASE_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;https://api.appstoreconnect.apple.com/v1&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Authorization&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Bearer &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;encoded_jwt&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;BASE_URL&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/preReleaseVersions&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;limit&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;filter[app]&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;APP_ID&lt;/span&gt;&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;build_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;data&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;build_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;data&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;attributes&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;version&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;BASE_URL&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/preReleaseVersions/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;build_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/builds&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;build_number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;data&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;attributes&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;version&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;App version: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;build_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Build number: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;build_number&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We want the developer to determine the next version after we get the last build number (like 154) and build name (like 2.3.0). Most of the time, we only need to increase the build number by one, which is why I included the if-else clause. If you leave the build number blank and press enter, it will add one to the previous build number.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;new_build_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Enter new app version: &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;new_build_number_str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Enter new build number(enter to auto increment): &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;new_build_number_str&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;''&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;new_build_number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;build_number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;new_build_number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new_build_number_str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;new_build_name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;''&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;No new version number entered&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 5: Build the app
&lt;/h2&gt;

&lt;p&gt;Now it's time to build the app, and we no longer require Python. We need the power Flutter cli to rescue us :)&lt;/p&gt;

&lt;p&gt;To run the terminal commands from python, we can use &lt;code&gt;subprocess.run&lt;/code&gt; in python.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;check&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shlex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;check&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;check&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DEVNULL&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cwd&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before building the IPA file, we have to make sure all the packages are updated and we have everything we need to build the project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Update dependencies
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Getting pub...&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;flutter pub get&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;check&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Installing pod dependencies...&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;rm ios/Podfile.lock&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;check&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;pod install --repo-update&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cwd&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ios/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;check&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, we use the following function to read the &lt;code&gt;pubspec.yaml&lt;/code&gt; file and change the &lt;code&gt;version: x.x.x+yyy&lt;/code&gt; with the new version we specified earlier in the input.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;change_pub_version&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;pubspec.yaml&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;^(version:\s*)(.+)&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;version: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MULTILINE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;pubspec.yaml&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;w&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can also remove the build folder to ensure there is nothing else in there before asking Flutter to create the IPA file for us. If you are using Flutter version 3+, You don't need to do anything; Flutter handles generating IPA for you.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# you can also specify version when building like this:
# `flutter build ipa --build-name {new_app_version} --build-number {new_build_number}`
&lt;/span&gt;&lt;span class="nf"&gt;change_pub_version&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;new_build_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;+&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;new_build_number&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;rm -rf build/ios&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;flutter build ipa --no-pub&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;check&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note: by default, flutter auto-generates some parameters from the pubspec file when building. If you haven't changed anything in the Xcode project, it will get the version from those parameters.&lt;br&gt;
If it doesn't work for you, you can follow &lt;a href="https://medium.com/karlmax-berlin/versioning-with-flutter-299869e68af4" rel="noopener noreferrer"&gt;this article&lt;/a&gt; or &lt;a href="https://stackoverflow.com/a/63914373/4614391" rel="noopener noreferrer"&gt;this answer&lt;/a&gt; to fix it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Step 6: Upload it to AppStore
&lt;/h2&gt;

&lt;p&gt;We successfully generated an IPA file in the previous step. It's now time to upload it. At this point, there are two options for manually uploading it, but what's the fun in that?&lt;br&gt;
We use &lt;code&gt;altool&lt;/code&gt; to upload the file for us. We also consider that uploading or verifying the file may fail, and in that case, we open the folder and &lt;a href="https://apps.apple.com/us/app/transporter/id1450874784" rel="noopener noreferrer"&gt;the Transporter application&lt;/a&gt;, so we can do it manually and determine what caused the error.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;xcrun altool --upload-app --type ios -f build/ios/ipa/*.ipa --apiKey &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;KEY_ID&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; --apiIssuer &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ISSUER_ID&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;returncode&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;open build/ios/ipa&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;open -n /Applications/Transporter.app&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 7: Add script to IDE
&lt;/h2&gt;

&lt;p&gt;Now that we've finished our Python script, let's make it easier to run. You can, of course, run it from the terminal, but there are better ways.&lt;/p&gt;

&lt;h3&gt;
  
  
  Android studio
&lt;/h3&gt;

&lt;p&gt;It is possible to add it as a run configuration and press run whenever you need it. Ensure that the &lt;code&gt;Working directory&lt;/code&gt; is the root path of your 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnsf5o00pvt585oc8aehk.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%2Fuploads%2Farticles%2Fnsf5o00pvt585oc8aehk.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  VSCode
&lt;/h3&gt;

&lt;p&gt;You can store it in the &lt;code&gt;.vscode/launch.json&lt;/code&gt; file as a run configuration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0.2.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"configurations"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Deploy iOS"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"python"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"request"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"launch"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"program"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"scripts/deploy_ios.py"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"console"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"integratedTerminal"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 8: Get rid of "Manage compliance"
&lt;/h2&gt;

&lt;p&gt;After uploading each TestFlight version to AppStore Connect, you will see the &lt;code&gt;Manage compliance&lt;/code&gt; warning. Apple won't roll out the new release for TestFlight users until you answer those two questions in the box.&lt;br&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%2Fuploads%2Farticles%2Fleq92xtysbh81dgpkbqy.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%2Fuploads%2Farticles%2Fleq92xtysbh81dgpkbqy.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This can be annoying when you want an automated process from start to finish. Luckily, &lt;a href="https://stackoverflow.com/a/35842359/4614391" rel="noopener noreferrer"&gt;this answer&lt;/a&gt; will help you get rid of it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bouns: Flavors
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.flutter.dev/deployment/flavors" rel="noopener noreferrer"&gt;Flavors&lt;/a&gt; are an excellent way to separate different environments. I recommend reading &lt;a href="https://flutterguide.com/flutter-flavor-separating-build-environments-in-flutter-apps/" rel="noopener noreferrer"&gt;this article&lt;/a&gt; for implementing them in Flutter.&lt;/p&gt;

&lt;p&gt;After adding different flavors to your project, you can create a new app in AppStore Connect for the dev version with different bundle identifier.&lt;/p&gt;

&lt;p&gt;In &lt;a href="https://gist.github.com/SamadiPour/34126da2c8bae567b3b0dd8a83bc8b66" rel="noopener noreferrer"&gt;this gist&lt;/a&gt;, I added an example for when you use different bundle identifier and you need to deploy them separately.&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>ios</category>
      <category>tutorial</category>
      <category>automation</category>
    </item>
  </channel>
</rss>
