-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.html
293 lines (196 loc) · 21.1 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html" charset="UTF-8" >
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="generator" content="I'm Amit Kothari">
<title>I'm Amit Kothari</title>
<meta name="author" content="Amit Kothari">
<link rel="alternative" type="application/atom+xml" title="RSS" href="/atom.xml">
<meta name="description" content="Traveller & Foodie, I write code for fun and living">
<meta property="og:type" content="blog">
<meta property="og:title" content="I'm Amit Kothari">
<meta property="og:url" content="http://amitkothari.com/index.html">
<meta property="og:site_name" content="I'm Amit Kothari">
<meta property="og:description" content="Traveller & Foodie, I write code for fun and living">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="I'm Amit Kothari">
<meta name="twitter:description" content="Traveller & Foodie, I write code for fun and living">
<meta name="twitter:creator" content="@amitkothari">
<!--STYLES-->
<link rel="stylesheet" href="/assets/css/style.min.css" type="text/css">
<!--STYLES END-->
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-70893413-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</head>
<body>
<div id="blog">
<!-- Define author's picture -->
<header id="header" data-behavior="4">
<i id="btn-open-sidebar" class="fa fa-lg fa-bars"></i>
<h1 class="header-title">
<a class="header-title-link" href="/ ">I'm Amit Kothari</a>
</h1>
<a class="header-right-picture "
href="/#about">
</a>
</header>
<!-- Define author's picture -->
<nav id="sidebar" data-behavior="4">
<ul class="sidebar-buttons">
<li class="sidebar-button">
<a class="sidebar-button-link "
href="/ "
>
<i class="sidebar-button-icon fa fa-lg fa-home"></i>
<span class="sidebar-button-desc">Home</span>
</a>
</li>
</ul>
<ul class="sidebar-buttons">
<li class="sidebar-button">
<a class="sidebar-button-link " href="https://github.com/amitkothari" target="_blank">
<i class="sidebar-button-icon fa fa-lg fa-github"></i>
<span class="sidebar-button-desc">GitHub</span>
</a>
</li>
<li class="sidebar-button">
<a class="sidebar-button-link " href="https://twitter.com/amitkothari" target="_blank">
<i class="sidebar-button-icon fa fa-lg fa-twitter"></i>
<span class="sidebar-button-desc">Twitter</span>
</a>
</li>
</ul>
<ul class="sidebar-buttons">
<li class="sidebar-button">
<a class="sidebar-button-link "
href="/atom.xml"
>
<i class="sidebar-button-icon fa fa-lg fa-rss"></i>
<span class="sidebar-button-desc">RSS</span>
</a>
</li>
</ul>
</nav>
<div id="main" data-behavior="4"
class="
hasCoverMetaIn
">
<section class="postShorten-group main-content-wrap">
<article class="postShorten postShorten--thumbnailimg-bottom" itemscope itemType="http://schema.org/BlogPosting">
<div class="postShorten-wrap">
<div class="postShorten-header">
<h1 class="postShorten-title" itemprop="headline">
<a class="link-unstyled" href="/Continuous-deployment-of-React-Native-app-using-Fastlane/">Continuous deployment of React Native app using Fastlane</a>
</h1>
<div class="postShorten-meta">
<time itemprop="datePublished" content="Tue Dec 08 2015 12:20:00 GMT+0530">
Dec 08, 2015
</time>
<span>in </span>
<a class="category-link" href="/categories/development/">development</a>, <a class="category-link" href="/categories/development/mobile-app/">mobile app</a>
</div>
</div>
<div class="postShorten-content" itemprop="articleBody">
<p>React Native has gained a lot of popularity since it was introduced and open-sourced by Facebook early this year. The framework uses JavaScript to build mobile apps and now supports both iOS and Android.</p>
<p>After playing with the framework, I decided to write a simple iOS app using react native and the first thing I wanted to do was to setup an automated deployment pipeline so that everytime I push new changes to my git repository, my continuous integration server can run the tests and upload the new app build to TestFlight.</p>
<p>I decided to use <a href="http://fastlane.tools" target="_blank" rel="external">Fastlane</a> which is an iOS automation toolset, recently acquired by Twitter and is now a part of <a href="https://fabric.io/" target="_blank" rel="external">Fabric</a>.</p>
<p>In this post I will go through the steps of creating a very simple React Native app and configuring Fastlane to deploy the app to TestFlight.</p>
<h3 id="Create_Hello_World_React_Native_App">Create Hello World React Native App</h3><p>Lets start by creating a simple React Native app which will show ‘Hello World’ text. </p>
<p>If you do not have React Native installed on your machine, please follow <a href="https://facebook.github.io/react-native/docs/getting-started.html" target="_blank" rel="external">these instructions</a>.</p>
<p>After installing React Native, you can use the CLI to create a new project ‘helloWorldApp’ by running following command.</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ react-native init helloWorldApp</span><br></pre></td></tr></table></figure>
<p>This command will fetch all the dependencies, including React Native source code and will create a new Xcode project for iOS and gradle project for Android.</p>
<p>Open ios/helloWorldApp.xcodeproj in Xcode and hit run button or press ⌘+r to run the project.</p>
<p>React Native entry file for the iOS app is index.ios.js . Open this file in your favourite editor and change the content of the render function to</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">render: <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <span class="xml"><span class="tag"><<span class="title">View</span> <span class="attribute">style</span>=<span class="value">{styles.container}</span>></span></span><br><span class="line"> <span class="tag"><<span class="title">Text</span> <span class="attribute">style</span>=<span class="value">{styles.welcome}</span>></span></span><br><span class="line"> Hello World</span><br><span class="line"> <span class="tag"></<span class="title">Text</span>></span></span><br><span class="line"> <span class="tag"></<span class="title">View</span>></span></span><br><span class="line"> )</span>;</span><br></pre></td></tr></table></figure>
<p>You can press ⌘+r to reload the app in the simulator for quick feedback cycle.</p>
<h3 id="Setup_Fastlane_for_automated_deployment">Setup Fastlane for automated deployment</h3><p>Now we have the hello world app working, we will setup Fastlane to work with our app.</p>
<h4 id="Create_offline_bundle">Create offline bundle</h4><p>The AppDelegate class initialise the app and load React Native JavaScript code. When the app is running in iPhone simulator, AppDelegate loads the JavaScript code from development server. To run the app without development server, we have to create an offline bundle and pack all the JavaScript code within the app. For this we can use React Native CLI bundle command, which will minify and bundle the JavaScript code to main.jsbundle</p>
<figure class="highlight armasm"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ react-native <span class="keyword">bundle </span>--<span class="preprocessor">entry</span>-file ./index.ios.js --platform ios --<span class="keyword">bundle-output </span>ios/main.jsbundle</span><br></pre></td></tr></table></figure>
<p>Now update the AppDelegate.m (ios/helloWorldApp/AppDelegate.m).</p>
<p>replace<br><figure class="highlight groovy"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">jsCodeLocation = [NSURL <span class="string">URLWithString:</span>@<span class="string">"http://localhost:8081/index.ios.bundle?platform=ios&dev=true"</span>];</span><br></pre></td></tr></table></figure></p>
<p>with<br><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="preprocessor">#<span class="keyword">ifdef</span> DEBUG</span></span><br><span class="line"> jsCodeLocation = [NSURL URLWithString:@<span class="string">"http://localhost:8081/index.ios.bundle?platform=ios&dev=true"</span>];</span><br><span class="line"> <span class="preprocessor">#<span class="keyword">else</span></span></span><br><span class="line"> jsCodeLocation = [[NSBundle mainBundle] URLForResource:@<span class="string">"main"</span> withExtension:@<span class="string">"jsbundle"</span>];</span><br><span class="line"> <span class="preprocessor">#<span class="keyword">endif</span></span></span><br></pre></td></tr></table></figure></p>
<h4 id="Initialise_Fastlane">Initialise Fastlane</h4><p>Follow <a href="https://github.com/KrauseFx/fastlane/blob/master/docs/Guide.md" target="_blank" rel="external">these instructions</a> to install Fastlane.</p>
<p>Once Fastlane is installed, run ‘fastlane init’ command to setup fastlane and create all the necessary files and folders. For this example, I have skipped delivery and snapshot steps.</p>
<p>Update fastlane/Fastfile file and replace beta config with this.</p>
<figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">lane </span>:beta do</span><br><span class="line"> sigh</span><br><span class="line"> </span><br><span class="line"> <span class="function">produce</span>(</span><br><span class="line"> <span class="attribute">username</span>: <span class="string">'<Apple ID>'</span>,</span><br><span class="line"> <span class="attribute">app_identifier</span>: <span class="string">'com.amitkothari.helloWorldApp'</span>, # Explicit app id</span><br><span class="line"> <span class="attribute">app_name</span>: <span class="string">'Unique App Name'</span>,</span><br><span class="line"> <span class="attribute">language</span>: <span class="string">'English'</span>,</span><br><span class="line"> <span class="attribute">app_version</span>: <span class="string">'1.0'</span>,</span><br><span class="line"> <span class="attribute">sku</span>: <span class="string">'HWAPP'</span>,</span><br><span class="line"> <span class="attribute">team_name</span>: <span class="string">'<Team Name>'</span> # only required when the Apple ID is assocaited with multiple teams</span><br><span class="line"> )</span><br><span class="line"></span><br><span class="line"> <span class="function">increment_build_number</span>(</span><br><span class="line"> <span class="attribute">xcodeproj</span>: <span class="string">'./ios/helloWorldApp.xcodeproj'</span></span><br><span class="line"> )</span><br><span class="line"></span><br><span class="line"> <span class="function">gym</span>(</span><br><span class="line"> <span class="attribute">scheme</span>: <span class="string">'helloWorldApp'</span>,</span><br><span class="line"> <span class="attribute">project</span>: <span class="string">'./ios/helloWorldApp.xcodeproj'</span></span><br><span class="line"> )</span><br><span class="line"></span><br><span class="line"> pilot</span><br><span class="line">end</span><br></pre></td></tr></table></figure>
<p><strong>Updated on 8 December 2015</strong></p>
<p><del>While Fastlane will take care of most of the stuff, we still need to register our app in Apple’s developer center. Login to <a href="https://developer.apple.com" target="_blank" rel="external">developer center</a> and setup the app in iOS Provisioning Portal and iTunes Connect with an explicit app id.</del></p>
<p>We are using Fastlane <a href="https://github.com/fastlane/produce" target="_blank" rel="external">produce</a> to register our app on Dev portal and iTunes Connect.</p>
<p>We also need to setup our app to auto increment app’s build and version number.<br><a href="https://developer.apple.com/library/ios/qa/qa1827/_index.html" target="_blank" rel="external">Follow these two steps</a> to enable agvtool and set up version and build number.</p>
<p>While you have the Xcode open, also set the bundle identifier (com.amitkothari.helloworldapp) and team under the general tab.</p>
<p>We also need to add app icon and launch screen images before uploading the app to TestFlight.</p>
<p>We can now create another entry in the package.json scripts, to bundle and deploy the app in a single command.</p>
<figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> "<span class="attribute">name</span>": <span class="value"><span class="string">"helloWorldApp"</span></span>,</span><br><span class="line"> "<span class="attribute">version</span>": <span class="value"><span class="string">"0.0.1"</span></span>,</span><br><span class="line"> "<span class="attribute">private</span>": <span class="value"><span class="literal">true</span></span>,</span><br><span class="line"> "<span class="attribute">scripts</span>": <span class="value">{</span><br><span class="line"> "<span class="attribute">start</span>": <span class="value"><span class="string">"react-native start"</span></span>,</span><br><span class="line"> "<span class="attribute">deploy</span>": <span class="value"><span class="string">"react-native bundle --entry-file ./index.ios.js --platform ios --bundle-output ios/main.jsbundle && fastlane beta"</span></span><br><span class="line"> </span>}</span>,</span><br><span class="line"> "<span class="attribute">dependencies</span>": <span class="value">{</span><br><span class="line"> "<span class="attribute">react-native</span>": <span class="value"><span class="string">"^0.15.0"</span></span><br><span class="line"> </span>}</span><br><span class="line"></span>}</span><br></pre></td></tr></table></figure>
<h3 id="Additional_steps">Additional steps</h3><ul>
<li><p>If your apple id is associated with multiple teams. You may get a prompt to select the team while running Fastlane command. To avoid this update fastlane/Appfile and enter team id and name.</p>
</li>
<li><p>If you get exportArchive or IDEDistributionErrorDomain error similar to <a href="https://github.com/fastlane/gym/issues/89" target="_blank" rel="external">this issue</a>, add ‘use_legacy_build_api: true’ under gym configuration.</p>
</li>
</ul>
<figure class="highlight gradle"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">gym(</span><br><span class="line"> scheme: <span class="string">'helloWorldApp'</span>,</span><br><span class="line"> <span class="keyword">project</span>: <span class="string">'./ios/helloWorldApp.xcodeproj'</span></span><br><span class="line"> use_legacy_build_api: <span class="keyword">true</span></span><br><span class="line"> )</span><br></pre></td></tr></table></figure>
<ul>
<li>If you get the following error</li>
</ul>
<blockquote>
<p>“Invalid Provisioning Profile. The provisioning profile included in the bundle com.amitkothari.helloWorldApp [Payload/helloWorldApp.app] is invalid. [Missing code-signing certificate]. A Distribution Provisioning profile should be used when submitting apps to the App Store. For more information, visit the iOS Developer Portal.”</p>
</blockquote>
<p>Open the app in Xcode and under the build setting tab, set code signing provisioning profile to “$(PROFILE_UUID)” . See the image below or read <a href="https://github.com/fastlane/fastlane/blob/master/docs/CodeSigning.md" target="_blank" rel="external">this</a> for more details.</p>
<img src="/Continuous-deployment-of-React-Native-app-using-Fastlane/image.png" alt="Set provisiong profile in Xcode" title="Set provisiong profile in Xcode">
<p>
<a href="/Continuous-deployment-of-React-Native-app-using-Fastlane/#post-footer" class="postShorten-excerpt_link link">
Comment and share
</a>
</p>
</div>
</div>
</article>
<div class="pagination-bar">
<ul class="pagination">
<li class="pagination-number">page 1 of 1</li>
</ul>
</div>
</section>
<footer id="footer" class="main-content-wrap">
<span class="copyrights">
Copyrights © 2015 Amit Kothari. All Rights Reserved.
</span>
</footer>
</div>
</div>
<!-- Define author's picture -->
<div id="about">
<div id="about-card">
<div id="about-btn-close">
<i class="fa fa-remove"></i>
</div>
<h4 id="about-card-name">Amit Kothari</h4>
<h5 id="about-card-bio"><p>author.bio</p>
</h5>
<h5 id="about-card-job">
<i class="fa fa-briefcase"></i>
<br/>
<p>author.job</p>
</h5>
<h5 id="about-card-location">
<i class="fa fa-map-marker"></i>
<br/>
Melbourne, Australia
</h5>
</div>
</div>
<div id="cover" style="background-image:url('/assets/images/cover.jpg');"></div>
</body>
<!--SCRIPTS-->
<script src="/assets/js/script.min.js" type="text/javascript"></script>
<!--SCRIPTS END-->
</html>