code-push/docs/tutorials.html

1189 строки
49 KiB
HTML
Исходник Постоянная ссылка Ответственный История

Этот файл содержит неоднозначные символы Юникода!

Этот файл содержит неоднозначные символы Юникода, которые могут быть перепутаны с другими в текущей локали. Если это намеренно, можете спокойно проигнорировать это предупреждение. Используйте кнопку Экранировать, чтобы подсветить эти символы.

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en-us">
<head>
<link href="http://gmpg.org/xfn/11" rel="profile">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta property="og:title" content="CodePush" />
<meta property="og:site_name" content="CodePush"/>
<meta property="og:description" content="CodePush Blog" />
<meta property="og:image" content="https://microsoft.github.io/code-push/assets/images/fbshare.PNG" />
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@Microsoft">
<meta name="twitter:title" content="CodePush">
<meta name="twitter:description" content="CodePush Blog">
<meta name="twitter:image" content="https://microsoft.github.io/code-push/assets/images/fbshare.PNG">
<!-- Enable responsiveness on mobile devices-->
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1">
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width" />
<meta name="description" content="CodePush Blog">
<title>
Tutorials &middot; CodePush
</title>
<!-- build:css /assets/css/vendor.css -->
<link rel="stylesheet" href="/code-push/libraries/bootstrap/dist/css/bootstrap.css" />
<link rel="stylesheet" href="/code-push/libraries/highlightjs/styles/solarized_light.css">
<link rel="stylesheet" href="/code-push/libraries/font-awesome/css/font-awesome.min.css">
<link rel="stylesheet" href="/code-push/libraries/github-fork-ribbon-css/gh-fork-ribbon.css">
<!-- endbuild -->
<!-- CSS -->
<!-- build:css /assets/css/style.min.css -->
<link rel="stylesheet" href="/code-push/assets/stylesheets/style.css">
<link rel="stylesheet" href="/code-push/assets/stylesheets/ga.style.css">
<!-- endbuild -->
<!-- Icons --> <!-- TODO: Check that these all wok -->
<link rel="apple-touch-icon" sizes="57x57" href="/code-push/assets/images/icons/apple-icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="/code-push/assets/images/icons/apple-icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="/code-push/assets/images/icons/apple-icon-72x72.png">
<link rel="apple-touch-icon" sizes="76x76" href="/code-push/assets/images/icons/apple-icon-76x76.png">
<link rel="apple-touch-icon" sizes="114x114" href="/code-push/assets/images/icons/apple-icon-114x114.png">
<link rel="apple-touch-icon" sizes="120x120" href="/code-push/assets/images/icons/apple-icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="/code-push/assets/images/icons/apple-icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="/code-push/assets/images/icons/apple-icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/code-push/assets/images/icons/apple-icon-180x180.png">
<link rel="icon" type="image/png" sizes="192x192" href="/code-push/assets/images/icons/android-icon-192x192.png">
<link rel="icon" type="image/png" sizes="32x32" href="/code-push/assets/images/icons/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="96x96" href="/code-push/assets/images/icons/favicon-96x96.png">
<link rel="icon" type="image/png" sizes="16x16" href="/code-push/assets/images/icons/favicon-16x16.png">
<link rel="manifest" href="/code-push/assets/images/icons/manifest.json">
<meta name="msapplication-TileColor" content="#294E80">
<meta name="msapplication-TileImage" content="/code-push/assets/images/icons/ms-icon-144x144.png">
<meta name="theme-color" content="#ffffff">
<!-- JS -->
<!-- Redirect logic from this docs(as it was depricated) to new docs https://docs.microsoft.com/en-us/appcenter/distribution/codepush/ -->
<script src="/code-push/assets/javascript/redirect.js"></script>
<!-- build:js /assets/js/vendors.js -->
<script src="/code-push/libraries/jquery/dist/jquery.min.js"></script>
<script src="/code-push/libraries/bootstrap/dist/js/bootstrap.js"></script>
<script src="/code-push/libraries/zeroclipboard/dist/ZeroClipboard.min.js"></script>
<script src="/code-push/libraries/anchorific.js/min/anchorific.min.js"></script>
<script src="/code-push/libraries/toc/dist/toc.min.js"></script>
<script src="/code-push/libraries/highlightjs/highlight.pack.min.js"></script>
<!-- endbuild -->
<!-- build:js /assets/js/all.min.js -->
<script src="/code-push/assets/javascript/global.js"></script>
<script src="/code-push/assets/javascript/home.js"></script>
<script src="/code-push/assets/javascript/docs.js"></script>
<script src="/code-push/assets/javascript/faq.js"></script>
<!-- endbuild -->
<!-- RSS -->
<link rel="alternate" type="application/rss+xml" title="RSS" href="/code-push/atom.xml">
</head>
<body>
<header role="banner">
<nav class="navbar navbar-default navbar-fixed-top">
<div class="container-fluid">
<!--<img class="fork-me-ribbon pull-right" src="../assets/images/fork_me_ribbon.svg" />-->
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle pull-left collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/code-push/index.html">
<img class="navbar-logo" src="/code-push/assets/images/codepush_navbar_logo.svg">
<sup class="navbar-logo-text">PREVIEW</sup>
</image>
</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse navbar_center" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li class=""><a href="/code-push/index.html#getting_started">Getting Started</a></li>
<li class="active"><a href="/code-push/docs/index.html">Documentation</a></li>
<li class=""><a href="/code-push/faq/index.html">FAQ</a></li>
<li class=""><a href="/code-push/blog/index.html">Blog</a></li>
<li class=""><a href="/code-push/community/friends.html">Showcase</a></li>
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>
</header>
<div class="top_navbar_spacer"></div>
<div class="docs">
<div id="content" class="container main_content">
<div class="col-md-3 toc-container hidden-sm hidden-xs">
<div class="row">
<div class='site-toc-container'>
<h2 class="site-toc-title">Table of Contents</h2>
<ul class="site-toc">
<li>
<a class="" href="/code-push/docs/getting-started.html">
Getting Started
</a>
</li>
<li>
<a class="this-page" href="/code-push/docs/tutorials.html">
Tutorials
</a>
<div id="page-toc" class="page-toc"></div>
</li>
<li>
<a class="" href="/code-push/docs/cli.html">
Management CLI
</a>
</li>
<li>
<a class="" href="/code-push/docs/node.html">
Management SDK
</a>
</li>
<li>
<a class="" href="/code-push/docs/cordova.html">
Cordova Client SDK
</a>
</li>
<li>
<a class="" href="/code-push/docs/react-native.html">
React Native Client SDK
</a>
</li>
<li>
<a class="" href="/code-push/docs/vsts-extension.html">
VSTS Extension
</a>
</li>
</ul>
</div>
</div>
</div>
<div class="col-md-7 col-md-offset-1">
<div class="row">
<div class="xs-toc-container visible-sm visible-xs">
<nav class='xs-toc'>
<div class="toc-dropdown dropdown">
<h2 class="site-toc-title">Table of Contents</h2>
<a class="dropdown-toggle btn" data-toggle="dropdown" href="#">
Select topic
<span class="caret"></span>
</a>
<ul class="dropdown-menu">
<li>
<a href=/code-push/docs/getting-started.html>Getting Started</a>
</li>
<li>
<a href=/code-push/docs/tutorials.html>Tutorials</a>
</li>
<li>
<a href=/code-push/docs/cli.html>Management CLI</a>
</li>
<li>
<a href=/code-push/docs/node.html>Management SDK</a>
</li>
<li>
<a href=/code-push/docs/cordova.html>Cordova Client SDK</a>
</li>
<li>
<a href=/code-push/docs/react-native.html>React Native Client SDK</a>
</li>
<li>
<a href=/code-push/docs/vsts-extension.html>VSTS Extension</a>
</li>
</ul>
</div>
</nav>
</div>
</div>
<div class="row">
<header class="doc-header">
<h1 class="doc-title">Tutorials</h1>
<!--<ul class="nav" style="display:inline-block;"><li><a class="edit-page-link" style="padding-left:0" href="https://microsoft.github.io/code-push_docs/Tutorials.md" target="_blank"><span class="glyphicon glyphicon-pencil"></span><i>&nbsp;</i>Edit on GitHub</a></li></ul>-->
</header>
<article class="doc-content">
<h2>Update experience configuration</h2>
<p>CodePush provides Cordova and React Native developers with multiple options to configure the end users update experience.</p>
<p>This tutorial covers three potential &ldquo;update modes&rdquo; or deployment strategies for CodePush updates: Silent, Active and Custom. Leveraging these options allow developers to control when (and how often) to check for updates as well as how to present any update notifications to end users.</p>
<blockquote>
<p><strong>Note:</strong> This tutorial does not cover how to enable CodePush on an app. If you need help setting up CodePush, visit the <a href="http://microsoft.github.io/code-push/docs/cordova.html#link-2">Cordova</a> or <a href="http://microsoft.github.io/code-push/docs/react-native.html#link-3">React Native</a> &ldquo;Getting Started&rdquo; sections.</p>
</blockquote>
<h3>1. Silent mode</h3>
<p>Silent mode updates are the simplest way to update an app and the least invasive experience for the end users.</p>
<div class="highlight"><pre><code class="language-javascript" data-lang="javascript">codePush.sync();
</code></pre></div>
<p>If an update is available, it will be silently downloaded, and installed the next time the app is restarted (either explicitly by the end user or by the OS). However, developers can modify the install behavior if they so choose, by leveraging the <code>installMode</code> parameter:</p>
<ul>
<li><strong>IMMEDIATE</strong>: The update will be applied to the running application immediately. The application will be reloaded with the new content immediately.</li>
<li><strong>ON_NEXT_RESTART</strong>: The update is downloaded but not installed immediately. The new content will be available the next time the application is started.</li>
<li><strong>ON_NEXT_RESUME</strong>: The update is downloaded but not installed immediately. The new content will be available the next time the application is resumed or restarted, whichever event happens first.</li>
</ul>
<p>For example, to download and install an update immediately, developers can use the <code>installMode</code> parameter as follows:</p>
<div class="highlight"><pre><code class="language-javascript" data-lang="javascript">codePush.sync({installMode: InstallMode.IMMEDIATE});
</code></pre></div>
<h4>Recommendation</h4>
<p>Depending on the complexity of the app, pushing an update immediately might be a jarring experience for end users (e.g. changing the UI or losing the current state can be frustrating and confusing). Because of this, we recommend updates are installed only after a certain period of app inactivity has been reached. To achieve this experience, developers can use the InstallMode.ON_NEXT_RESUME and minimumBackgroundDuration parameters as follows:</p>
<div class="highlight"><pre><code class="language-javascript" data-lang="javascript">// Download the update silently, but install on next
// app resume and after 10 minutes of app inactivity
// We recommend doing this call on app start (e.g. `componentDidMount` event on React Native or `deviceready` on Cordova)
codePush.sync({ installMode: InstallMode.ON_NEXT_RESUME, minimumBackgroundDuration: 60 * 10 });
</code></pre></div>
<blockquote>
<p><strong>Note:</strong> If <code>codePush.sync()</code> is not called on app start (e.g. <code>componentDidMount</code> event on React Native or <code>deviceready</code> on Cordova), developers will need to notify the update was successfully installed by calling the <code>codePush.notifyApplicationReady()</code> method. Otherwise the CodePush runtime will assume the installed update has failed and roll back to the previous version.</p>
<p><strong>Note:</strong> For Cordova, the first parameter that <code>codePush.sync()</code> expects is a <code>syncStatusCallback</code>, so to do the same thing, you should insert <code>null</code> as the first parameter to the call, i.e:</p>
</blockquote>
<div class="highlight"><pre><code class="language-javascript" data-lang="javascript">codePush.sync(null, { installMode: InstallMode.ON_NEXT_RESUME, minimumBackgroundDuration: 60 * 10 });
</code></pre></div>
<h3>2. Active mode</h3>
<p>In contrast to the silent mode updates, active mode updates prompt end users about available updates and thus require user interaction.</p>
<p>The difference is introduced by the usage of the <code>updateDialog</code> parameter.</p>
<div class="highlight"><pre><code class="language-javascript" data-lang="javascript"> codePush.sync({ updateDialog: true });
</code></pre></div>
<p>If an update is available, the app automatically launches a native prompt asking end users for permission to download and install the update. Once the user accepts, the update is silently downloaded and inmmediatly applied., and installed the next time the app is restarted (either explicitly by the end user or by the OS).</p>
<h4>Update dialog customization</h4>
<p>To customize the update dialog, developers can create an updateDialogOption object and pass it to the <code>codePush.sync()</code> call as follows:</p>
<div class="highlight"><pre><code class="language-javascript" data-lang="javascript">
var updateDialogOptions = {
updateTitle: &quot;You have an update&quot;,
optionalUpdateMessage: &quot;Update available. Install?&quot;,
optionalIgnoreButtonLabel: &quot;Nop&quot;,
optionalInstallButtonLabel: &quot;Yep&quot;,
};
codePush.sync({ updateDialog: updateDialogOptions});
</code></pre></div>
<p>Visit the <a href="http://microsoft.github.io/code-push/docs/cordova.html#link-5">Cordova</a> or <a href="http://microsoft.github.io/code-push/docs/react-native.html#link-8">React Native</a> API Reference pages for a full description of all the avaiable UpdateDialogOptions options.</p>
<blockquote>
<p><strong>Note:</strong> While Apples developer agreement fully allows performing over-the-air updates of JavaScript and assets (which is what enables CodePush!), it is against their policy for an app to display an update prompt. Because of this, we recommend that App Store-distributed apps dont enable the updateDialog option when calling sync, whereas Google Play and internally distributed apps (e.g. Enterprise, Fabric, HockeyApp) can choose to enable/customize it.</p>
</blockquote>
<h3>3. Custom mode</h3>
<p>Custom mode provides the flexibility to customize any stage of the update experience such as providing a custom &ldquo;checking for updates&rdquo; or &ldquo;downloading&rdquo; notification.</p>
<h4>Update cycle notifications</h4>
<p>The <code>codePush.sync()</code> method allows the use of a call back to hook into the overall update process and thus provide a custom experience on each stage of the update process as follows.</p>
<div class="highlight"><pre><code class="language-javascript" data-lang="javascript">var onSyncStatusChange = function(SyncStatus) {
switch (SyncStatus) {
case SyncStatus.CHECKING_FOR_UPDATE:
// Show &quot;Checking for update&quot; notification
break;
case SyncStatus.AWAITING_USER_ACTION:
// Show &quot;Checking for update&quot; notification
break;
case SyncStatus.DOWNLOADING_PACKAGE:
// Show &quot;downloading&quot; notification
break;
case SyncStatus.INSTALLING_UPDATE:
// Show &quot;installing&quot; notification
break;
}
}
// Prompt the user when an update is available and display a &quot;downloading&quot; modal
codePush.sync({ updateDialog: true }, onSyncStatusChange);
</code></pre></div>
<p>Visit the <a href="http://microsoft.github.io/code-push/docs/cordova.html#syncstatus">Cordova</a> or <a href="http://microsoft.github.io/code-push/docs/react-native.html#syncstatus">React Native</a> SyncStatus enum for a full description of all the available enum values.</p>
<h4>Adding a &ldquo;downloading&rdquo; progress indicator</h4>
<p>To provide an enhanced experience, developers can choose to provide a download progress indicator. The <code>codePush.sync()</code> method provides a different call back to make this possible.</p>
<div class="highlight"><pre><code class="language-javascript" data-lang="javascript">
var onError = function (error) {
console.log(&quot;An error occurred. &quot; + error);
};
var onDownloadProgress = function (downloadProgress) {
if (downloadProgress) {
console.log(&quot;Downloading &quot; + downloadProgress.receivedBytes + &quot; of &quot; + downloadProgress
}
};
codePush.sync({ updateDialog: true }, onSyncStatusChange, onDownloadProgress, onError);
</code></pre></div>
<h2>Automate your deployments with VSTS</h2>
<p>Continuous Integration (CI) and Continuous Deployment (CD) are key practices of DevOps. It requires the team to have a mindset to merge all working copies of developers code with a shared repository, producing a new build upon code commit. In turn this provides them with the opportunity to leverage the CI output, deploy it to one or more environments, and ultimately serve the end users via app updates.</p>
<p>This tutorial covers how to leverage Visual Studio Team Services (VSTS) and CodePush in order to create a CD environment to automate app updates from an existing CI environment. Even though a &ldquo;proper&rdquo; CI build not only compiles the code, but ideally runs code analysis, unit (and sometimes even integration) tests and even could package the code, those CI details wont be discussed but instead go over the basics of CI integration as well as details of how to setup the CD environment.</p>
<h3>Overview</h3>
<p>VSTS is a collection of services that let teams share code, track work, and ship software—for any language.</p>
<p>From a high-level it provides developers with:</p>
<ul>
<li>Unlimited free private code repositories</li>
<li>Ability to track bugs, work items, feedback, and more</li>
<li>Agile planning tools</li>
<li>Continuous integration builds</li>
<li>Enterprise-grade services scale to any team size</li>
<li>Free for up to five users</li>
</ul>
<p>In addition, VSTS allows developers to extend the service by creating VSTS extensions that can help with tasks covering the full CI and CD spectrum.</p>
<p>The CodePush service provides a VSTS extension with a set of deployment tasks that allows the automation of releases and the promotion of app updates directly from your CI environment.</p>
<p>Leveraging the workflow discussed below can greatly reduce the effort needed to keep your dev/alpha/beta deployments up-to-date, since you can simply push changes to the configured source control branches, and let your automated build take care of the rest. No need to manually release, promote or rollout from the CodePush CLI!</p>
<h3>Prerequisites</h3>
<p>The following is required to complete this module:</p>
<ul>
<li>VSTS Account (Sign up for a free VSTS account <a href="https://www.visualstudio.com/products/free-developer-offers-vs">here</a>)</li>
<li>CodePush Account (Follow these <a href="http://microsoft.github.io/code-push/docs/getting-started.html#link-0">steps</a> to create an account)</li>
<li>React Native &ldquo;CodePush ready&rdquo; <a href="https://github.com/rub8n/VSTSCDSample">sample app</a> (Use your own app or download the &ldquo;bare bones&rdquo; sample app to speed things up)</li>
</ul>
<blockquote>
<p><strong>Note:</strong> For simplicity purposes, the steps covered below are done using the Android platform of the React Native sample project above. However, most of the steps also apply for both React Native iOS and Cordova projects.</p>
</blockquote>
<h3>1. Register your app with CodePush</h3>
<p>Start by registering your app with the CodePush service:
<code>
code-push app add VSTSCDSample-Android android react-native
</code></p>
<p>The CodePush CLI will provide you with a set of deployment keys:
<img src="/code-push/assets/images/docs/tutorials/vsts/cli-keys.png" alt="CodePush CLI providing deployment keys"></p>
<p>Save the <code>Staging</code> deployment key as it will be used to set up your project.</p>
<h3>2. Add a CodePush deployment key</h3>
<p>Download the <a href="#">React Native sample project</a> and open the strings.xml file located under the sample app&rsquo;s <code>android &gt; app &gt; src &gt; main &gt; res &gt; values</code>.</p>
<p>Navigate to line #2 and add the previously recorded <code>Staging</code> deployment key:</p>
<p><img src="/code-push/assets/images/docs/tutorials/vsts/replace-key.png" alt="Adding new deployment keys"></p>
<h3>3. Push the source code to a VSTS team project</h3>
<p>Create a new project in VSTS by clicking on <code>New</code>:</p>
<p><img src="/code-push/assets/images/docs/tutorials/vsts/vsts-home.png" alt="Create new VSTS project"></p>
<p>Give it a name and ensure <code>Git</code> is selected for <code>Version control</code>:</p>
<p><img src="/code-push/assets/images/docs/tutorials/vsts/vsts-new.png" alt="New project dialog"></p>
<p>Once the project is created, copy the remote string as you will use it to update the local repository&rsquo;s remote URL to point to your new VSTS project:</p>
<p><img src="/code-push/assets/images/docs/tutorials/vsts/vsts-remote.png" alt="Getting VSTS remote"></p>
<p>Update the repository&rsquo;s remote URL using the following <a href="https://help.github.com/articles/changing-a-remote-s-url">command</a>:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"> git remote set-url origin replaceWithVSTSRepositoryURL
</code></pre></div>
<p>Once the new remote URL is set, push the repository to VSTS via <a href="https://help.github.com/articles/pushing-to-a-remote/">Git push</a></p>
<div class="highlight"><pre><code class="language-text" data-lang="text"> git push -u origin --all
</code></pre></div>
<p>A few seconds later, the source will be added to your VSTS repository:</p>
<p><img src="/code-push/assets/images/docs/tutorials/vsts/vsts-code.png" alt="New project dialog"></p>
<h3>4. Configure the CI environment</h3>
<h4>Install VSTS extension</h4>
<p>To build the project you will need to install an extension from the VSTS Marketplace.</p>
<p>For React Native projects do the following:</p>
<ol>
<li> In the upper right corner, click the Basket icon and select Browse Marketplace.</li>
</ol>
<p><img src="/code-push/assets/images/docs/tutorials/vsts/vsts-marketplace.png" alt="Open the VSTS marketplace"></p>
<ol>
<li> Enter the term <code>react</code> in the search box and press enter. Open and install the <code>React Native</code> VSTS extension made by the <code>Visual Studio Client Tools</code> team:</li>
</ol>
<p><img src="/code-push/assets/images/docs/tutorials/vsts/vsts-market-react.png" alt="Browse the VSTS marketplace"></p>
<h4>Create a new build definition</h4>
<ol>
<li>In the top menu bar, click BUILD to open the build hub. In the menu on the left, click the green + button to create a new build definition.</li>
</ol>
<p><img src="/code-push/assets/images/docs/tutorials/vsts/vsts-new-definition.png" alt="Creating new VSTS build definition"></p>
<ol>
<li>Select <code>Empty</code> from the list of build templates and click <code>Next</code>.</li>
</ol>
<p><img src="/code-push/assets/images/docs/tutorials/vsts/vsts-selecting-definition.png" alt="Selecting empty definition"></p>
<ol>
<li>Make sure that the repo settings are correct (it should be the master branch on the VSTSCDSample repo). Check the <code>Continuous integration</code> checkbox and ensure that the Default agent queue is set to Hosted and click <code>Create</code>.</li>
</ol>
<p><img src="/code-push/assets/images/docs/tutorials/vsts/vsts-empty-definition.png" alt="Configuring empty definition"></p>
<blockquote>
<p><strong>Note</strong>: The <code>Continuous Integration</code> trigger tells VSTS to kick-off an instance of this build each time code is pushed to the <code>master</code> branch.</p>
</blockquote>
<h4>Configure the build task</h4>
<p>As part of the CI build configuration process, you&rsquo;ll add a series of steps that will build the project and publish an artifact (the Android bundle), which the CD environment will use to update the app.</p>
<p><img src="/code-push/assets/images/docs/tutorials/vsts/vsts-build-steps.png" alt="Build steps"></p>
<p>Create the described build definition by following these steps:</p>
<ol>
<li><p>Install npm dependencies by clicking on <code>Add build step...</code> and adding <code>npm</code> from the <code>Package</code> category. Select it and specify the following settings:</p>
<ul>
<li>Use <code>install</code> as the <code>Command</code></li>
</ul></li>
<li><p>Add a new build step to remove any previously created &ldquo;artifacts&rdquo; folder by adding <code>Command Line</code> from the <code>utility</code> category. Select it and specify the following settings:</p>
<ul>
<li>Use <code>rm</code> as the <code>Tool</code></li>
<li>Use <code>-rf artifacts</code> as the <code>Arguments</code></li>
</ul></li>
<li><p>Add a new build step to make a new &ldquo;artifacts&rdquo; folder by adding a <code>Command Line</code> from the <code>utility</code> category. Select it and specify the following settings:</p>
<ul>
<li>Use <code>mkdir</code> as the <code>Tool</code></li>
<li>Use <code>artifacts</code> as the <code>Arguments</code></li>
</ul></li>
<li><p>Add a new build step to add <code>React Native Prepare</code> from the <code>Build</code> category. Select it and specify the following settings:</p>
<ul>
<li>Select <code>Android</code> as the <code>Platform</code></li>
<li>Use <code>android/app/build.gradle</code> as the <code>react.gradle Path</code></li>
</ul></li>
<li><p>Add a new build step to add <code>React Native Bundle</code> from the <code>Build</code> category. Select it and specify the following settings:</p>
<ul>
<li>Select <code>Android</code> as the <code>Platform</code></li>
<li>Use <code>index.android.js</code> as the <code>Entry File</code></li>
<li>Use <code>./artifacts/index.android.bundle</code> as the <code>Bundle Output</code></li>
<li>Use <code>./artifacts</code> as the <code>Asset Destination Path</code></li>
</ul></li>
<li><p>Add a new build step to publish the created artifacts (in this context the Android bundle created by running <code>React Native Bundle</code>) by adding <code>Publish Build Artifacts</code> from the <code>utility</code> category. Select it and specify the following settings:</p>
<ul>
<li>Use <code>./artifacts</code> as the <code>Path to Publish</code></li>
<li>Use <code>Artifacts</code> as the <code>Artifact Name</code></li>
<li>Use <code>Server</code> as the <code>Artifact Type</code></li>
</ul></li>
<li><p>Save and name the build definition by pressing the <code>Save</code> toolbar button.</p></li>
</ol>
<p>You can manually queue a new build to test the build process by pressing the <code>Queue build...</code> toolbar button.</p>
<p><img src="/code-push/assets/images/docs/tutorials/vsts/vsts-build-queue.png" alt="Build queue"></p>
<p>Pressing <code>OK</code> on the &ldquo;Queue build&rdquo; dialog starts the build process:</p>
<p><img src="/code-push/assets/images/docs/tutorials/vsts/vsts-build-running.png" alt="Build running"></p>
<blockquote>
<p><strong>Note</strong>: The previously set <code>Continuous Integration</code> trigger ensures new builds are automatically queued every time code is pushed to the <code>master</code> branch.</p>
</blockquote>
<h3>5. Configure the CD environment</h3>
<p>As a best practice, we recommend creating three release environments: &ldquo;Staging&rdquo;, &ldquo;Rollout&rdquo; and &ldquo;Production&rdquo;. This configuration allows you to continuously deploy to &ldquo;Staging&rdquo;, rollout to a small percentage of production users and finally release to all production users when confidence is high.</p>
<h4>Install VSTS extension</h4>
<p>To leverage the CodePush service as the release vehicle, you will need to install another extension from the VSTS Marketplace.</p>
<ol>
<li> In the upper right corner, click the Basket icon and select Browse Marketplace.</li>
</ol>
<p><img src="/code-push/assets/images/docs/tutorials/vsts/vsts-marketplace.png" alt="Open the VSTS marketplace"></p>
<ol>
<li> Enter the term <code>codepush</code> in the search box and press enter. Open and install the <code>React Native</code> VSTS extension made by the <code>Visual Studio Client Tools</code> team:</li>
</ol>
<p><img src="/code-push/assets/images/docs/tutorials/vsts/vsts-market-codepush.png" alt="Browse the VSTS marketplace"></p>
<h4>Create a new release definition</h4>
<ol>
<li>In the top menu bar, click RELEASE to open the release hub. In the menu on the left, click the green + button to create a new release definition.</li>
</ol>
<p><img src="/code-push/assets/images/docs/tutorials/vsts/vsts-new-release-definition.png" alt="Creating new VSTS release definition"></p>
<ol>
<li>Select <code>Empty</code> from the list of release templates and click <code>Next</code>.</li>
</ol>
<p><img src="/code-push/assets/images/docs/tutorials/vsts/vsts-selecting-release-definition.png" alt="Selecting empty definition"></p>
<ol>
<li>Make sure that the project settings are correct (the source should point towards the previously created build definition). Check the <code>Continuous deployment</code> checkbox and ensure that the agent queue is set to <code>Hosted</code> and click <code>Create</code>.</li>
</ol>
<p><img src="/code-push/assets/images/docs/tutorials/vsts/vsts-empty-release-definition.png" alt="Configuring empty definition"></p>
<blockquote>
<p><strong>Note</strong>: The <code>Continuous deployment</code> trigger tells VSTS to kick-off a release each time a successful build completes. This behavior can be modified to release automatically or after a release is formally approved.</p>
</blockquote>
<h4>Configure the deployment task</h4>
<p>For the actual CD tasks, you&rsquo;ll create a staging environment that will release updates via CodePush after every successful build. Followed by two production environments that will initially target a small fixed amount of production users and eventually all production users.</p>
<p><img src="/code-push/assets/images/docs/tutorials/vsts/vsts-release-enviroments.png" alt="Release environments"></p>
<p>Create the described release definition by following these steps:</p>
<ol>
<li><p>Rename the default environment to <code>Staging</code> by clicking on the &ldquo;Environment 1&rdquo; label, typing the new name and pressing enter.</p></li>
<li><p>Use the <code>CodePush CLI</code> to create an access key for VSTS by typing <code>code-push access-key add &quot;VSTS integration&quot;</code>. Save the key for the next step.</p></li>
<li><p>Back to VSTS, configure the <code>Staging</code> environment to release CodePush updates to users in the &ldquo;staging ring&rdquo; by clicking on <code>Add tasks</code> and selecting <code>CodePush - Release</code> from the <code>Deploy</code> category. Select it and specify the following settings:</p>
<ul>
<li>Use <code>Access Key</code> as the <code>Authentication Method</code></li>
<li>Use the key created in the previous step as the <code>Access Key</code></li>
<li>Use <code>VSTSCDSample-android</code> (or the app name used when registering the app with CodePush if different) as the <code>App Name</code></li>
<li>Use <code>Staging</code> as the <code>Deployment</code></li>
<li>Use the browse button to set <code>Update Contents Path</code> to point towards the &ldquo;Artifacts&rdquo; folder created during the build process.</li>
</ul></li>
<li><p>Add a second environment and name it <code>Rollout</code> by clicking on <code>Add environment</code> then on &ldquo;Create new environment&rdquo;. Select <code>Empty</code>, press <code>Next</code> and specify the following settings:</p>
<ul>
<li>Set <code>Specific users</code> under <code>Pre-deployment approval</code> to control what users decide to approve deployments to the <code>Rollout</code> environment.</li>
<li>Select the <code>trigger</code> to ensure this step kicks off automatically after the <code>Staging</code> release completes.</li>
</ul></li>
<li><p>Configure the environment to target only a fixed number of production users, by clicking on &ldquo;Add tasks&rdquo; and selecting <code>CodePush - Promote</code> from the <code>Deploy</code> category. Select it and specify the following settings:</p>
<ul>
<li>Use <code>Access Key</code> as the <code>Authentication Method</code></li>
<li>Use the key created in the previous step as the <code>Access Key</code></li>
<li>Use <code>VSTSCDSample-android</code> (or the app name used when registering the app with CodePush if different) as the <code>App Name</code></li>
<li>Use <code>Staging</code> as the <code>Source Deployment</code></li>
<li>Use <code>Production</code> as the <code>Destination Deployment</code></li>
<li>Use <code>20%</code> for <code>Rollout</code> in order to deploy to only 20% of your production users</li>
</ul></li>
<li><p>Save and name the release definition by pressing the Save toolbar button.</p></li>
<li><p>Add a third environment and name it <code>Production</code> by clicking on <code>Add environment</code> then on &ldquo;Create new environment&rdquo;. Select <code>Empty</code>, press <code>Next</code> and specify the following settings:</p>
<ul>
<li>Set <code>Specific users</code> under <code>Pre-deployment approval</code> to control what users decide to approve deployments to the <code>Rollout</code> environment.</li>
<li>Select the <code>trigger</code> to ensure this step kicks off automatically after the <code>Rollout</code> release completes.</li>
</ul></li>
<li><p>Configure the environment to target all remaining production users, by clicking on &ldquo;Add tasks&rdquo; and selecting <code>CodePush - Patch</code> from the <code>Deploy</code> category. Select it and specify the following settings:</p>
<ul>
<li>Use <code>Access Key</code> as the <code>Authentication Method</code></li>
<li>Use the key created in the previous step as the <code>Access Key</code></li>
<li>Use <code>VSTSCDSample-android</code> (or the app name used when registering the app with CodePush if different) as the <code>App Name</code></li>
<li>Use <code>Production</code> as the <code>Deployment</code></li>
<li>Use <code>Latest</code> as the <code>Release Label</code></li>
<li>Use <code>100%</code> for <code>Rollout</code> in order to deploy to all remaining production users</li>
</ul></li>
<li><p>Save and name the release definition by pressing the Save toolbar button.</p></li>
</ol>
<h4>Testing your Staging deployments</h4>
<p>If you had both <code>Staging</code> and <code>Production</code> users, you could test the full release environment as configured. Since that&rsquo;s not the case for this tutorial, you can focus on testing the <code>Staging</code> environment.</p>
<p>To test the automated workflow, you&rsquo;ll need deploy a &ldquo;release&rdquo; version of the test app and push a change to the master branch in order to kick off a build and eventually a release.</p>
<p>You can create a &ldquo;release&rdquo; version of the app by generating a signed APK and installing the release build created with it. Instructions can be found on the <a href="http://facebook.github.io/react-native/docs/signed-apk-android.html#content">React Native docs</a>.</p>
<p>Deploy the app per the instructions linked above, do a small code change and commit the change to master.</p>
<p>VSTS allows you to edit the source code on the CODE hub:
<img src="/code-push/assets/images/docs/tutorials/vsts/vsts-code-change.png" alt="VSTS code changes"></p>
<h3>Summary</h3>
<p>This tutorial shows how VSTS and CodePush make your developer experience better. From a high level, VSTS provides teams with great tools and allows them to fully automate the build and release process while CodePush provides the flexibility to deploy automated updates from Staging to Production.</p>
</article>
<div class="feedback-container">
<div class="widget">
<div class="widget-error" style="display:none">
<div class="header">
<h3>Server trouble... ☹</h3>
</div>
<div class="message">
<P>We appreciate the effort but we are having issues.</P>
</div>
</div>
<div class="widget-thankyou" style="display:none">
<div class="header">
<h3>Thank you!</h3>
</div>
<div class="message">
<P>We appreciate your feedback.</P>
</div>
</div>
<div class="widget-message" style="display:none">
<div class="header">
<h3>Additional feedback</h3>
<!--<span class="charCount">1000</span>-->
</div>
<textarea class="form-control widget-text" maxlength="1000" rows="4"></textarea>
<div class="buttons">
<button type="submit" onclick="updateFeed(true)">Submit</button>
<button type="submit" onclick="updateFeed()">Skip this</button>
</div>
</div>
<div class="widget-entry">
<div class="header">
<h3> Was this documentation helpful?</h3>
</div>
<div class="buttons">
<button onclick="sendFeed(1)">Yes</button>
<button onclick="sendFeed(0)"> No</button>
</div>
</div>
</div>
</div>
<script>
var baseURL="https://docsfeedback.azurewebsites.net/api/feedback/";
var feedbackType, messageId;
var docURL = window.location.host+window.location.pathname;
var date = new Date().toUTCString();
var project = "CodePush";
function sendFeed(feedType){
feedbackType = feedType;
$.ajax({
method: "POST",
contentType: "application/x-www-form-urlencoded",
crossDomain: true,
cors: true,
url: baseURL+"create",
data: { Type: feedbackType, ParentURL: docURL, Project: project, CreationDate: date, Id: messageId}
})
.done(function(result, textStatus, xhr) {
messageId = xhr.responseJSON.Id;
$('.widget-entry').css('display','none');
$('.widget-message').css('display','block');
})
.fail(function(req, status, error ) {
console.log( 'Something went wrong - ', status, error );
$('.widget-entry').css('display','none');
$('.widget-error').css('display','block');
});
}
function updateFeed(msg){
var comments = $('.widget-text').val();
if(msg){
$.ajax({
method: "PUT",
contentType: "application/x-www-form-urlencoded",
crossDomain: true,
cors: true,
url: baseURL+messageId,
data: { Type: feedbackType, ParentURL: docURL, Project: project, CreationDate: date, Id: messageId, Message: comments}
})
.done(function() {
$('.widget-message').css('display','none');
$('.widget-thankyou').css('display','block');
})
.fail(function(req, status, error ) {
console.log( 'Something went wrong - ', status, error );
$('.widget-message').css('display','none');
$('.widget-error').css('display','block');
});
}
else{
$('.widget-message').css('display','none');
$('.widget-thankyou').css('display','block');
}
setTimeout(function(){
$('.widget').fadeTo( "slow", 0);
},4000);
}
</script>
</div>
</div>
</div>
</div>
<footer>
<div class="footer-container">
<div class="container" id="footer">
<div class="row">
<div class="col-sm-9">
<div class="row">
<div class="col-sm-4">
<h4>General</h4>
<ul class="nav">
<!--TODO: CHECK LINKS-->
<li><a href="https://github.com/Microsoft/code-push/blob/master/LICENSE.md" target="_blank">License</a></li>
<li><a href="https://www.visualstudio.com/en-us/privacy-policy-vs" target="_blank">Privacy</a></li>
<li><a href="https://msdn.microsoft.com/en-us/cc300389" target="_blank">Terms of Service</a></li>
</ul>
</div>
<div class="col-sm-4">
<h4>Community</h4>
<ul class="nav">
<li><a href="https://github.com/Microsoft/code-push/" target="_blank">GitHub Project</a></li>
<li><a href="https://stackoverflow.com/questions/tagged/codepush" target="_blank">Stack Overflow</a></li>
<li><a href="https://twitter.com/hashtag/codepush" target="_blank">#CodePush</a></li>
</ul>
</div>
<div class="col-sm-4">
<h4>Documentation</h4>
<ul class="nav">
<li><a href="https://github.com/Microsoft/code-push/blob/master/cli/README.md" target="_blank">CLI Docs</a></li>
<li><a href="https://github.com/Microsoft/cordova-plugin-code-push/blob/master/README.md" target="_blank">Cordova Plugin Docs</a></li>
<li><a href="https://github.com/Microsoft/react-native-code-push/blob/master/README.md" target="_blank">React Native Plugin Docs</a></li>
</ul>
</div>
</div>
</div>
<div class="col-sm-3">
<h3><i class="fa fa-comment"></i> Talk to us!</h3>
<p>If you have any feedback or suggestions on how we can make CodePush more awesome, please contact via Twitter <a href="https://twitter.com/mscodepush">@mscodepush, <a href=mailto:codepush@microsoft.com>email us</a> or ping us in the <a href="https://discord.gg/0ZcbPKXt5bWxFdFu">#code-push</a> channel on Reactiflux (for React Native).</p>
</div>
</div>
</div>
</div>
<div class="container-fluid signature-container">
<div class="container">
<div class="row signature">
<p class="pull-left hidden-xs">Made with <span class="glyphicon glyphicon-heart"></span> in Redmond</p>
<div class="pull-right">
<p class="copyright pull-left">&copy;2012-2017 Microsoft
<img class="ms-logo-footer" src="/code-push/assets/images/Microsoft_logo.svg"/></p>
</div>
</div>
</div>
</div>
</footer>
</body>
</html>