<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Jaison Fernando on Medium]]></title>
        <description><![CDATA[Stories by Jaison Fernando on Medium]]></description>
        <link>https://medium.com/@jaisonfdo?source=rss-3e6ad8e6ea74------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*jqNmBukjy4NU3eGUO8w3IQ.jpeg</url>
            <title>Stories by Jaison Fernando on Medium</title>
            <link>https://medium.com/@jaisonfdo?source=rss-3e6ad8e6ea74------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Fri, 13 Nov 2026 20:52:15 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@jaisonfdo/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[Introducing Dark Mode in Vookmark Android app]]></title>
            <link>https://medium.com/@jaisonfdo/introducing-dark-mode-in-vookmark-android-app-bdd6f0bafedf?source=rss-3e6ad8e6ea74------2</link>
            <guid isPermaLink="false">https://medium.com/p/bdd6f0bafedf</guid>
            <category><![CDATA[themes]]></category>
            <category><![CDATA[dark-mode]]></category>
            <category><![CDATA[vookmark]]></category>
            <category><![CDATA[androiddev]]></category>
            <category><![CDATA[development]]></category>
            <dc:creator><![CDATA[Jaison Fernando]]></dc:creator>
            <pubDate>Mon, 18 Mar 2019 03:40:55 GMT</pubDate>
            <atom:updated>2019-03-18T06:27:55.379Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*HIOQKMQVrV1sIm-ghuJFpA.jpeg" /></figure><p>Hey folks, this post is the story about the development of dark mode feature in Vookmark Android app. We’re starting with a feature that we know you’re already excited about. We announced Dark Mode back in Jan and the response was huge so we know you’ve been waiting with bated breath ever since.</p><p>So we prioritised the feature in line with the high popularity. Instead of just adding some black backgrounds &amp; flipping colours, we decided to restyle some of the modules for this Dark Mode, while still maintaining Vookmark’s look &amp; feel. We’re very proud of how sexy this Dark Mode has come to be. 🤭</p><h4>Why we introduced Dark mode feature in Vookmark?</h4><p>In recent years, millions of Android users have been insisting on Google enable dark themes on their Android phones. So Google has added a dark mode in Android 9.0+, which not only looks cool, is easier on your eyes and helps you to save on battery life.</p><p>Google has started providing support for dark themes in all Android’s core applications. So we are also following Googles footprints, and no more frying your retinas at night time. Whether you’re a night owl who wants to give your eyes rest or you just want to change things up a bit, you’ll find something to love while watching the bookmarked videos at night. In fact, you can watch more videos because of better power management. Yay, it’s available right now on every platform — Android, iOS, and Web.</p><h4>What are the ways to achieve this feature?</h4><p>Theme changes use case is often in Android application development, that there is a setting, button or checkbox which can switch between different colour themes or between something like day and night mode. We can achieve this use case using one of the below solutions.</p><p><strong>1. Recursively change attributes on all your Views:</strong></p><p>This way, when the theme is changed, you can loop through all the Views, again and again, to change the attributes to reflect the new theme.</p><pre>public void recursiveViews(ViewGroup parent) {</pre><pre>  for (int i = parent.getChildCount() - 1; i &gt;= 0; i--) <br>  {<br>       final View child = parent.getChildAt(i);<br>       if (child instanceof TextView) {<br>           (TextView) child).setTextColor(...);<br>       } else if (child instanceof Button){<br>           (Button) child).setTextColor(...);<br>       } <br>         // ... check other views<br>  }</pre><pre>}</pre><p>As it’s not about changing two or three colours in the main views, in order to keep your code clean, it’s better to do the changes on the XML files and not dynamically via Java code. Loop through all the views will <strong>decrease the app performance, increase the loading time and the code complexity</strong>.</p><p><strong>2. Duplicate layouts for each of your themes:</strong></p><p>By creating the separate layouts for every theme for a single screen and set the layout as content view while initialising the activity.</p><blockquote>LightThemeLayout:</blockquote><pre>&lt;RelativeLayout<br>    ....<br>    android:background=&quot;<strong>@color/windowbackgroundLight</strong>&quot;&gt;<br>    &lt;TextView<br>        android:id=&quot;@+id/stats_provider&quot;<br>        android:textColor=&quot;<strong>@color/textColorPrimaryLight</strong>&quot; /&gt;<br>&lt;/RelativeLayout&gt;</pre><blockquote>DarkThemeLayout:</blockquote><pre>&lt;RelativeLayout<br>    ....<br>    android:background=&quot;<strong>@color/windowbackgroundDark</strong>&quot;&gt;<br>    &lt;TextView<br>        android:id=&quot;@+id/stats_provider&quot;<br>        android:textColor=&quot;<strong>@color/textColorPrimaryDark</strong>&quot; /&gt;<br>&lt;/RelativeLayout&gt;</pre><blockquote>LayoutSwitchingActivity:</blockquote><pre>public class HomeActivity extends AppCompatActivity {</pre><pre>  @Override<br>  protected void onCreate(Bundle savedInstanceState) <br>  {<br>      super.onCreate(savedInstanceState);<br>   <br>      if(isDarkMode) <br>          setContentView(R.layout.activity_home_light);<br>      else<br>          setContentView(R.layout.activity_home_dark);<br>   }<br>}</pre><p>The only difference between each layout is that the style or in-line style-related attributes. This will increase the number of layout and code duplication while adding screens for every theme. This approach is very simple however, <strong>it will increase the code complexity. Same time it will increase the APK size as well because of the number of layout files</strong>.</p><p><strong>3. Changing the theme at runtime(*Recommended solution*):</strong></p><p>To make it work, We have to create separate Styles, by sharing the same base. A Style is a reusable form of a collection of resources. By the way, A theme is also a collection of resources which modifies look and feel of your product. The minor difference is you apply theme on a bigger level, say a screen(Activity) and you usually apply style on a granular level, say a view(Button, TextView..).</p><p>Here are the actual styles for the home activity:</p><pre>&lt;!-- Light theme --&gt;</pre><pre>&lt;style name=&quot;BaseActivityThemeLight&quot; parent=&quot;ActivityTheme.Primary.Base.Light&quot;&gt;<br>    &lt;item name=&quot;android:windowBackground&quot;&gt;#FFFFFF&lt;/item&gt;<br>&lt;/style&gt;</pre><pre>&lt;!-- Dark theme --&gt;</pre><pre>&lt;style name=&quot;BaseActivityThemeDark&quot; parent=&quot;ActivityTheme.Primary.Base.Dark&quot;&gt;<br>    &lt;item name=&quot;android:windowBackground&quot;&gt;#000000&lt;/item&gt;<br>&lt;/style&gt;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*XFUs38l6hXWTg7ynOYDU0w.png" /><figcaption>Vookmark — Home page — DarkMode</figcaption></figure><p>Applying a different theme that, the one specified into the manifest file must be done before calling the parent <strong>onCreate()</strong> method.</p><pre>public class HomeActivity extends AppCompatActivity {</pre><pre>  @Override<br>  protected void onCreate(Bundle savedInstanceState) <br>  {<br>      super.onCreate(savedInstanceState);</pre><pre>      if(isDarkMode) <br>          setTheme(R.style.BaseActivityThemeDark);<br>      else<br>          setTheme(R.style.BaseActivityThemeLight);</pre><pre>      setContentView(R.layout.activity_home);<br>  }<br>}</pre><p>This approach is a bit complex because we have to define the themes for the individual views based on the application style. <strong>It will decrease the code complexity since we reuse the layouts as it is. Same time a granular level of increase in the APK size</strong>.</p><h4>How we achieved it?</h4><p>In line with Android’s own guidelines, we’ve kept things clean and simple in Dark Mode with proper use of colour and by using the material design theming guidelines.</p><p>We achieved this feature by <strong>changing the theme at runtime</strong> based on the user&#39;s style selection.</p><h4>How to enable/disable the Vookmark app’s new Dark Mode?</h4><p>To turn on the feature, the obvious first step is to make sure that you have the version of Vookmark (v3.2.7) or above.</p><p>Once the update installs, it’s just a matter of tapping the Settings from the slider menu, the “Dark Mode” toggle is under the theme settings. It’s disabled by default, and activating it will cause the page refresh. However, Vookmark returns with an easy-on-the-eyes dark theme. It’s not completely black, we still maintaining Vookmark’s look and feel.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ejwaGjEZu6noCR2gykvzlQ.png" /><figcaption>Vookmark-DarkMode-Switch-Guide</figcaption></figure><h4>What is next?</h4><p>We hope you’ll like our new dark look and enjoy our Vookmark service even more. In the meanwhile, we’ll be working on what’s next for Vookmark.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*PjlCNQt9f0F5_w6V-66obA.jpeg" /><figcaption>DayNight mode</figcaption></figure><p>Now that we’ve implemented flexible Dark Mode, go wild — we can switch themes automatically based on the time of day or based on the system-wide dark mode setting.</p><h4>Didn’t grab Vookmark yet?</h4><p>Vookmark is a place to collect all your favourite videos in one place. Ever stumbled upon an awesome video and cannot watch it immediately? Vookmark solves that problem too. Keep a permanent collection of video links you love and watch them everywhere.</p><p>Vookmark allows you to add videos easily from top video platforms like YouTube, Facebook, Vimeo, DailyMotion, Reddit. You can watch all your videos on Vookmark for Android, Web, iPhone, iPad or Apple TV.</p><p><a href="https://vookmark.co/"><strong>Get started with Vookmark.</strong></a></p><p>Hope this post will help you to get your head around Dark Mode and its Android implementation.</p><p>Please continue to share your feedback and suggestions to us on <a href="/service/mailto:team@vookmark.co">team@vookmark.co</a> and help us to spread the word about Vookmark on social media with <strong>#vookmark</strong> and tagging <a href="http://twitter.com/getVookmark"><strong>@getVookmark</strong></a> as well as in real life!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=bdd6f0bafedf" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to add In-App Purchase in your Android app?]]></title>
            <link>https://medium.com/@jaisonfdo/how-to-add-in-app-purchase-in-your-android-app-545b85e5d5d?source=rss-3e6ad8e6ea74------2</link>
            <guid isPermaLink="false">https://medium.com/p/545b85e5d5d</guid>
            <category><![CDATA[subscription]]></category>
            <category><![CDATA[android]]></category>
            <category><![CDATA[in-app-purchase]]></category>
            <dc:creator><![CDATA[Jaison Fernando]]></dc:creator>
            <pubDate>Fri, 28 Sep 2018 11:20:06 GMT</pubDate>
            <atom:updated>2018-10-03T05:59:19.969Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*M8QYbD9cJMFGu1Zzfa9QEA.png" /><figcaption><a href="https://unsplash.com/photos/8lnbXtxFGZw">Photo</a> by <a href="https://unsplash.com/@sharonmccutcheon">Sharon</a></figcaption></figure><p>In-app purchase (IAP) is a great way to earn money from your Android app. IAP is mostly used to unlock some additional features in your app that you want to monetise from. Monetisation is one of the most important aspects of distributing your product to the rest of the world. Like it or not, Google charges 30% of each successful transaction that your app will make.</p><p>Based on the available API’s we can classify IAP products into two types.</p><h3>Managed in-app products:</h3><p>Products are managed by the developer, you can decide if you want to handle your managed products as non-consumable or consumable items.</p><ul><li><strong>Consumable product:</strong> It is usually temporary and, once consumed, can be bought again, For example, the user’s in-game character might gain life points or gain extra gold coins in their inventory.</li><li><strong>Non-consumable product:</strong> It can only be purchased once in your application and provide a permanent benefit. Once purchased, these products will be permanently associated with the user’s Google account. For example, upgrading an app to pro version, or removing ads</li></ul><h3>Subscriptions:</h3><p>A payment that will unlock features of your app for a limited amount of time(days, weeks, months, years). Billing continues indefinitely at the interval and price specified for the subscription. When a subscription is not renewed, the product is no longer active for the user.</p><p>With this tutorial, you will learn everything that you need to know about In-App Purchases. I will try to be as much detailed as possible, and will break down this tutorial to multiple steps for better understanding:</p><p>Let’s begin!</p><ol><li>Adding the Play Billing Library to your app</li><li>Configuring products</li><li>Implementing Purchase helper to your app</li><li>Get purchase history</li><li>Get product details</li><li>Initiating a Google Play In-app Billing Purchase</li><li>Redirects to Manage Subscription</li><li>Cancel an active subscription</li></ol><p>After implementing this IAP in multiple projects, I thought why not this be done with a single util class. So I’ll explain the above-mentioned steps using the helper class.</p><h3>1. Adding the Play Billing Library to your app:</h3><p>Just add the following dependency in your project.</p><pre>implementation ‘com.android.billingclient:billing:1.1’</pre><p>Add internet permission in your AndroidManifest.xml file. Embedded billing permission inside the library’s manifest. It’s not necessary to add the com.android.vending.BILLING permission inside Android manifest anymore.</p><pre>&lt;! — To use internet → &lt;uses-permission android:name=”android.permission.INTERNET” /&gt;</pre><pre>&lt;uses-permission android:name=”android.permission.INTERNET” /&gt;</pre><p>… sync your project.</p><h3>2. Configuring the products:</h3><p>In order to have the IAP within your app, you must first configure your in-app products using the Google Play Console. Since this article is more oriented towards play-billing library implementation, I won’t get into too much detail about how to configure the products. I suggest you read this by yourself from the official documentation because it’s quite self-explanatory with examples too.</p><p><a href="https://support.google.com/googleplay/android-developer/answer/1153481">Create a managed product</a><br><a href="https://support.google.com/googleplay/android-developer/answer/140504">Create a subscription</a></p><p>Sounds easy enough, right?</p><h3>3. Implementing Purchase helper to your app:</h3><p>To implement our PurchaseHelper util into your app, you need to declare and define the object with the callback interface (PurchaseHelperListener), which will give you the response of your specific query. You can use the following code snippet</p><pre>PurchaseHelper purchaseHelper;</pre><pre>purchaseHelper = <strong>new</strong> PurchaseHelper(<strong>this</strong>, getPurchaseHelperListener());</pre><pre>public PurchaseHelper.PurchaseHelperListener getPurchaseHelperListener() {</pre><pre><strong>return</strong> <strong>new</strong> PurchaseHelper.PurchaseHelperListener() {</pre><pre>@Override</pre><pre>public <strong>void</strong> onServiceConnected(<strong>int</strong> resultCode) {</pre><pre>Log.d(TAG, &quot;onServiceConnected: &quot; + resultCode);</pre><pre>}</pre><pre>@Override</pre><pre>public <strong>void</strong> onSkuQueryResponse(List&lt;SkuDetails&gt; skuDetails) {</pre><pre>}</pre><pre>@Override</pre><pre>public <strong>void</strong> onPurchasehistoryResponse(List&lt;Purchase&gt;  purchasedItems) {</pre><pre>purchaseHistory = purchasedItems;</pre><pre>}</pre><pre>@Override</pre><pre>public <strong>void</strong> onPurchasesUpdated(<strong>int</strong> responseCode, @Nullable List&lt;Purchase&gt; purchases) {</pre><pre>Log.d(TAG, &quot;onPurchasesUpdated: &quot; + responseCode);</pre><pre>}</pre><pre>};<br>}</pre><h3>4. Get the purchase history</h3><p>Before launching the billing flow we have to check the status of the product, to check the history of the purchase. You can make the request to get all the already purchased items. You can achieve this by making a simple function call</p><pre>// You can pass BillingClient.SkuType.INAPP || BillingClient.SkuType.SUBS purchaseHelper.getPurchasedItems(TYPE);</pre><p>It will return the response of this request into our callback function <strong>onPurchasehistoryResponse(List purchasedItems)</strong>. From this, we can get all the purchases in the specific SkuType which is connected with the specific app and the Google account which is active in the device Google play.</p><h3>5. Get the product details</h3><p>To show the details about the products, we have to get the details from our play console using the product ID. For this, we have to pass the list of product IDs and the SkuType. You can get the product details by using the following snippet.</p><pre>purchaseHelper.getSkuDetails(skuList,BillingClient.SkuType.INAPP);</pre><p>It will return the response of this request into our callback function <strong>onSkuQueryResponse(List skuDetails);</strong>.</p><h3>6. Initiating a Google Play In-app Billing Purchase</h3><p>To initiate the In-app Billing Purchase, you have to pass <strong>SkuType</strong> and the <strong>product ID</strong></p><pre>purchaseHelper.launchBillingFLow(BillingClient.SkuType.INAPP, getProduct_id());</pre><p>It will return the response of this request into our callback function <strong>onPurchasesUpdated(int responseCode, @Nullable List purchases)</strong>. We can implement the logic here to consume the purchased item.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*u-emZDuf6RIGdb-y2v0Oxg.jpeg" /></figure><h3>7. Redirects to Manage Subscription</h3><p>To manage our subscriptions, in the earlier days, we could redirect the users only to the Play Store on your app’s page and the user have to figure out where to click next to cancel the subscription. But now In 2018 I/O, the play billing team included a nice add-on, that we can easily redirect the user to the “Manage subscription” page for your app.</p><p>You can do this by using the following function call, the single line makes your life easier.</p><pre>purchaseHelper.gotoManageSubscription();</pre><h3>8. Cancel an active subscription:</h3><p>In Android, Currently, the Google Play Billing library does not provide support for programmatically cancelling subscriptions from inside the purchasing app. It is only available within the Play Store app.</p><p>We can cancel the subscriptions via Google Play Developer API. To cancel the subscription we need the following parameters</p><ol><li>The package name of the app</li><li>Purchased subscription ID</li><li>PurchaseToken provided to the user’s when the subscription was purchased.</li></ol><p>As a developer, we never like to provide an option to cancel the subscription. But this will be more useful to the user. If the user likes our app and the subscribed feature, then they will never use this option. If the user cancels a subscription, it will remain valid until its expiration time.</p><p><strong>Bonus tip:</strong></p><p>The renewal period will vary from 5 to 30 minutes, depending on the original billing period. In addition to this, previously they are limiting the number of times a test subscription can be renewed only 6 times, now it is unlimited.</p><p><strong>Code:</strong></p><p>The sample <a href="https://github.com/jaisonfdo/PurchaseHelper">app</a> is very simple and it covers almost all common use cases, doesn’t consider all the use cases you will need in your app; keep that in mind before loading the copy-paste machine gun.</p><p>The source code is available on <a href="https://github.com/jaisonfdo/PurchaseHelper">GitHub</a>,</p><p>One more thing to do, before executing the project you have to change the <strong>“applicationId”</strong> in the build.gradle(app) and also the <strong>“product_id”</strong> in the city_list.json file which is in the assets folder.</p><p>That’s it, now you can run the project, and voilà! It works like a champ.</p><p>Let me know how your IAP implementation went in the comments below. Now you can implement IAP into your app and start generating some revenue by selling your app.</p><p><em>Originally published at </em><a href="https://droidmentor.com/inapppurchase-subscription/"><em>droidmentor.com</em></a><em> on September 28, 2018.</em></p><p>Enjoyed the story? Leave some claps 👏 here on Medium and share it with your friends. Want to stay up-to-date on the latest in Android app dev? Follow me on Twitter. I won’t spam your feed. 😄</p><p><a href="https://twitter.com/jaisonfdo">Jaison Fernando (@jaisonfdo) | Twitter</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=545b85e5d5d" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Why Google Play In-App Subscription in Vookmark?]]></title>
            <link>https://medium.com/@jaisonfdo/why-google-play-in-app-subscription-in-vookmark-20a8affbb790?source=rss-3e6ad8e6ea74------2</link>
            <guid isPermaLink="false">https://medium.com/p/20a8affbb790</guid>
            <category><![CDATA[in-app-purchase]]></category>
            <category><![CDATA[subscription]]></category>
            <category><![CDATA[android]]></category>
            <category><![CDATA[google-play-services]]></category>
            <category><![CDATA[google-play-store]]></category>
            <dc:creator><![CDATA[Jaison Fernando]]></dc:creator>
            <pubDate>Fri, 13 Jul 2018 02:35:39 GMT</pubDate>
            <atom:updated>2018-07-13T02:35:59.396Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*Z8hV3G6gJVj_F1QdZg8TWA.jpeg" /></figure><h4><strong>What is Vookmark?</strong></h4><p>There are many bookmark managers like pocket but we don’t have something specific for videos.So we decided build one and that’s the reason for Vookmark’s existence.</p><p>Most of the bookmarking services store just the url and redirect you when you visit their dashboard. Vookmark allows you to watch all videos in one place without messy redirections.</p><h4><strong>Why we choose subscription business model?</strong></h4><p>The subscription business model is one of the best ways to make more regular, reliable, and recurring revenue for multi-platform apps. In fact, both developers and users love subscription apps.</p><p>This monetisation strategy is very similar to one known as <strong>Freemium</strong> (Free to Premium). “Try first, then buy” — this is the key principle we followed in <a href="https://vookmark.co/">Vookmark</a>. The app is free to download and offers some basic features but locks out premium features, which need to be purchased to extend the app’s functionality.</p><h4>Why we choose Google Play In-App Subscription for Android?</h4><p>I guess you have a doubt that, why we implement multiple payment sources(Google-play, AppStore and <a href="https://codeburst.io/stripe-our-saviour-in-payment-process-5b9705f09707">Stripe</a>) for a single app. We wants to provide the hazel free experience to our users, during this free to premium transition and also we have couple of reasons for this Google play in-app subscription implementation, they are listed below</p><ol><li>Google Play provides several <a href="https://android-developers.googleblog.com/search/label/subscriptions"><strong>subscription specific reports</strong></a> in the Google Play Console. It contains <strong>acquisition report, retention report, cancellations report.</strong></li><li>Google Play also enables you to offer 3-day free trials (rather than previously a minimum of 7 days). From this our users are perceiving the value of the premium service.</li><li>Google Play lets you offer multiple payment options across countries with a trusted, reliable, and easy 2-step checkout process.</li><li>Google play provides<strong> </strong><a href="https://developer.android.com/google/play/billing/billing_subscriptions.html#realtime-notifications"><strong>Real-time developer notifications</strong></a> feature, it informs you of any change in subscriber state in real time, such as cancellation or suspension, so you can act on the information immediately.</li><li>Google Play now makes restoring a subscription much easier with the new <a href="https://developer.android.com/google/play/billing/billing_subscriptions.html#restore"><strong>subscription restore</strong></a> feature. Using this feature user can restore the cancelled subscription until the expiration date.</li></ol><h4>Google play In-app subscription implementation:</h4><p>Google provides an easy to use library that is able to handle the subscriptions and querying tasks. In this <a href="https://developer.android.com/google/play/billing/billing_library"><strong>library</strong></a>, Google Play provides a straightforward, simple interface for sending In-app Billing requests and managing In-app Billing transactions.</p><p>While implementing <a href="http://developer.android.com/google/play/billing/billing_subscriptions.html">In App Subscription</a>s we found that the process of implementing it was not that complicated, but there were some hidden facts that took us time to figure out. It deserves a separate tech blog post. We are planning to write one soon. Keep watching this space for updates.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Zku3_wRX_v7EJRkjEPDOmg.png" /></figure><h4>How we achieve multi-platform payment process using Google play In-app subscription?</h4><p>When the user made a successful purchase request, we will get a receipt for a particular transaction, we are just forwarding this receipt payload to our Vookmark server and validating it in the server.</p><p>For this validation, Google provides receipt validation through the <a href="https://developers.google.com/android-publisher/">Google Play Developer API</a>, within the API, there are two endpoints: <a href="https://developers.google.com/android-publisher/api-ref/purchases/products/get">Purchases.products: get</a> and <a href="https://developers.google.com/android-publisher/api-ref/purchases/subscriptions/get">Purchases.subscriptions: get</a>.</p><p>In our case we are using <a href="https://developers.google.com/android-publisher/api-ref/purchases/subscriptions/get">Purchases.subscriptions: get</a> is for verifying and re-verifying auto-renewing product subscriptions. To use this API we must know the <strong>packageName</strong>, <strong>productID</strong> and <strong>purchaseToken </strong>all of these can be found in the receipt payload we received during purchase.</p><p>We need an <strong>access token</strong> which we can get by creating a Google API service account. To get started with a service account go to the Google play Developer console API access settings page and Link your project with the service account, which will help us to validate the purchase detail using Google play Developer API.</p><h4><strong>Write once, run anywhere</strong></h4><p>Though we used multiple payment mediums for payment process, but we consolidate everything in our server. So the payment triggering point is different, order receipt payload is different, the validating mechanism is also different, but we clubbed everything together and make it as a unified payment platform and provide the seamless experience to our users across all platforms.</p><p><strong>For detailed Backend Integration check this medium post by one of our team member.</strong></p><p><a href="https://medium.com/@ameer_86319/how-we-manage-payments-across-multiple-platforms-in-vookmark-3d1ce4bb1463">How we manage payments across multiple platforms in Vookmark 🤑💸</a></p><p><strong>Give a try and enjoy the seamless cross platform application for video bookmaking at </strong><a href="https://vookmark.co/"><strong>Vookmark</strong></a><strong>.</strong></p><p>Happy Vookmarking ! 😎</p><p>Happy Earning! 🤑</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=20a8affbb790" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to setup CI & CD for Android? — Part 2]]></title>
            <link>https://medium.com/@jaisonfdo/how-to-setup-ci-cd-for-android-part-2-d67549c8fba1?source=rss-3e6ad8e6ea74------2</link>
            <guid isPermaLink="false">https://medium.com/p/d67549c8fba1</guid>
            <category><![CDATA[android]]></category>
            <category><![CDATA[continuous-integration]]></category>
            <category><![CDATA[jenkins]]></category>
            <category><![CDATA[automation]]></category>
            <category><![CDATA[productivity]]></category>
            <dc:creator><![CDATA[Jaison Fernando]]></dc:creator>
            <pubDate>Mon, 12 Feb 2018 09:44:59 GMT</pubDate>
            <atom:updated>2018-02-12T14:33:52.824Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*E0eO6_MWBwKKPDY-wXxmiw.png" /></figure><p>This article is a part of <strong>How to setup CI &amp; CD for Android</strong> series. In my <a href="https://medium.com/@jaisonfdo/how-to-setup-ci-cd-for-android-projects-with-jenkins-and-gitlab-acb390a6aa3f">previous article</a>, I described CI &amp; CD and also explained the automation process.</p><p>In this article, I’m going to explain setup process of Jenkins server and Gitlab account. I’ll cover this entire implementation on macOS.</p><p><strong>Step 1 : Jenkins server setup</strong></p><p>Jenkins server is available for download on their <a href="https://jenkins.io/">official site</a>. Alternatively you can install Jenkins using homebrew (<em>brew install jenkins</em>). At the end of the installation, it will automatically redirect your browser to <a href="http://localhost:8080/">http://localhost:8080</a> which is the local address of your Jenkins.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*4g3iMKw_KRseHR0zt7O6kg.png" /><figcaption>Admin password setup</figcaption></figure><p>In the first launch you will need to unlock Jenkins, using the <strong>initialAdminPassword</strong>, because only admin can access the <strong>secrets </strong>directory. For more details regarding this basic setup, please take a look <a href="https://jenkins.io/doc/book/installing/">here</a>.</p><p>Finally, your Jenkins instance is up and running now!</p><blockquote>Note : The Jenkins user has been created (/Users/Shared/Jenkins) by default. So keep in mind that all files and variables declared under the default user will not be visible for Jenkins. To resolve this issue, your Android SDK needs to be installed in one of the shared folders like <em>/usr</em> or <em>/opt.</em></blockquote><p>To implement CI/CD automation process, you have to install the following plugins on Jenkins server by using Manage Jenkins &gt; Manage Plugins</p><ol><li>Android Emulator Plugin</li><li>Git Plugin</li><li>Gradle Plugin</li><li>Android Lint Plugin</li><li>Android Signing Plugin</li><li>Fabric Beta Publisher</li><li>Google Play Android Publisher Plugin</li></ol><p>After the successful installation of the above listed plugins, restart the Jenkins server.</p><p><strong>Step 2 : Gitlab configuration :</strong></p><p>To configure Gitlab with Jenkins, a common user account needs to be created. Log in to the Gitlab server as an administrator. After that create a repository to store your codebase in GitLab and change it with version control.</p><p>In Gitlab you can create repositories with Public/Private access. Anyone can access the public repositories with the remote URL. If you have a private repository you need to create an ssh key for your Jenkins and add it to your GitLab.</p><p>Before you dive deep,.. make sure Jenkins Server and Gitlab Account are already setup and running.</p><p><strong>Step 3 :</strong> <strong>Integrate Gitlab with Jenkins:</strong></p><p>For this integration, first create a SSH key pair to access the private repository, after this you have to add our public key as a deploy key to our Gitlab account and add the private key as a Jenkins Credential.</p><p>1. Adding your public key as a deploy key in Gitlab, go to your Gitlab Profile Settings &gt;SSH Keys and add an SSH Key</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*NGke4H9psn0FZ_1fRS4AGw.png" /></figure><p>2. Then add your private key as a Jenkins credential. For this go to Jenkins server, Jenkins &gt; Credentials &gt; System &gt; Global Credentials &gt; Add Credentials</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*iXjy1bLpe4TgIBZONH5Rsw.png" /></figure><p>3. Next, Jenkins needs your Gitlab API access token to get the metadata from Gitlab. To create the access token, go to your Gitlab Profile Settings &gt; Access Tokens and create an Access token.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*p6Fu9Ib9EQktWL7XItkHOQ.png" /></figure><p>4. Add the above created access token as a Jenkins credential. For this create a API token credential using Jenkins &gt; Credentials &gt; System &gt; Global Credentials &gt; Add Credentials.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/936/1*IIVBtSvvoJTZHyFqkBbJbQ.png" /></figure><p>5. Once the API Access has been setup, we can configure the connection between Jenkins and GitLab. To make this happen go toJenkins &gt; Manage Jenkins &gt; Configure System &gt; Gitlab Section and create a <strong>connection</strong> by using the above added GitLab API token</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/912/1*F-Af7msJXxDwPucHixLafA.png" /></figure><p>Finally, we have completed the basic Jenkins set up and now we are ready to create our First Job for a CI and deployment process. So lets start the same without much delay.</p><p><strong>Step 4 : Basic job setup</strong></p><p>For job creation, go to Jenkins &gt; New Item and now enter a valid Job title and select FreeStyle Project.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*bE5tpSce0OCjb17EEEt7TA.png" /></figure><p>In the <strong>General Section</strong> give the project name and select our connection(above created) as GitLab connection and all the other fields there are self explanatory.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*wVZl0mMl8RFq4YilDsrnaA.png" /></figure><p>In the <strong>Source Code Management Section</strong>, place your repository URL(SSH), select the above added SSH Jenkins credential and select a particular branch for this job or leave it empty. I would recommend not to leave it as empty.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/846/1*RlYg3RWGWwboNIDHi5MVog.png" /></figure><p><strong>Step 5: Configure Jenkins — Build Triggers :</strong></p><p>In this section, select the build triggering events based on our requirement(in our case we have to trigger this build generation on every push and every merge request).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*c1G6gs7A5F8SpxKIBovofQ.png" /></figure><p>Then create a secret token from Advanced tab, it will be used, while setting up the webhooks in Gitlab.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*I53gBSXWJ_4C0B-iFMSlaQ.png" /></figure><p><strong>Step 6: Configure Jenkins — Post-Build Actions</strong></p><p>Next thing what we have to do is configuring the post action of the project build completion. For this example, we have to add an action to change the commit status as <em>Completed</em>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*5uGztfoQJHC6omrdb1tftw.png" /></figure><p>That’s it, now we completed the Jenkins setup, at next we need to do the GitLab setup to trigger the build for every push and every merge request. For this we can use <strong>webhooks</strong>.</p><p><strong>Step 7: Configure Gitlab Webhooks :</strong></p><p>To create a webhooks we need our Jenkins URL and secret token. For creating these webhooks, go to your repository <strong>Integration Settings</strong> and do the changes, which is mentioned in the below image.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*kvPWz9tS0MzOe1eLz0dNzw.png" /></figure><blockquote>Note: By default Jenkins runs on your local machine. To make it available from the outer world you need to deal with services like <a href="https://www.heroku.com/">Heroku</a> or <a href="https://aws.amazon.com/">AWS</a>. If you want something really simple and fast here is a tool called <a href="http://ngrok.com/">ngrok</a> available. Two steps installation allows to create a tunnel to your localhost and generate a secure public URL.</blockquote><p>Once we complete the above mentioned steps, now we can change the gitlab commit status into passed/completed without human intervention.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*aDW0cLq51t4KXjqjm1HszA.png" /></figure><p>Now everything should be set! If you push a commit / make a merge request to the repository, you should see the Jenkins job start running. Once the job completes, you should see the status next to the commit in GitLab.</p><p><strong>What’s next?</strong></p><p>In the next part of this series, we will be focusing on Android Build Configuration &amp; Automation process. See you in next post!.</p><p>Hope to see you again soon.</p><p>Enjoyed the story? Leave some claps 👏 here on Medium and share it with your friends. Want to stay up-to-date on the latest in Android app dev? Follow me on Twitter. I won’t spam your feed. 😄</p><p><a href="https://twitter.com/jaisonfdo">Jaison Fernando (@jaisonfdo) | Twitter</a></p><p>Check all the top articles at <a href="http://droidmentor.com/">http://droidmentor.com/</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d67549c8fba1" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to setup CI & CD for Android projects with Jenkins and Gitlab?]]></title>
            <link>https://medium.com/@jaisonfdo/how-to-setup-ci-cd-for-android-projects-with-jenkins-and-gitlab-acb390a6aa3f?source=rss-3e6ad8e6ea74------2</link>
            <guid isPermaLink="false">https://medium.com/p/acb390a6aa3f</guid>
            <category><![CDATA[android-app-development]]></category>
            <category><![CDATA[continuous-integration]]></category>
            <category><![CDATA[automation]]></category>
            <category><![CDATA[android]]></category>
            <category><![CDATA[productivity]]></category>
            <dc:creator><![CDATA[Jaison Fernando]]></dc:creator>
            <pubDate>Sun, 07 Jan 2018 17:09:38 GMT</pubDate>
            <atom:updated>2018-02-15T03:30:02.006Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*E0eO6_MWBwKKPDY-wXxmiw.png" /></figure><p>This is the first part of a series of articles that will give you a complete walkthrough for setting up a CI &amp; CD environment for your Android projects.</p><p>In small projects, developers can do tasks manually with regards to building projects, testing and deployment. When the project grows exponentially it will become a big headache.</p><blockquote>Automate more, so you do less.</blockquote><p>As a developer, your aim is to automate as many processes as possible. Work hard in order to work less. In our case by setting up a CI system you can ship updates more often and with less (zero) effort on your part.</p><blockquote>So, what is a Continuous Integration?</blockquote><p><strong><em>Continuous Integration (CI)</em></strong> is the process of automating the build every time a team member commits changes to version control.</p><p>There are plenty of continuous integration platforms, some you can set up on your own machine while the other offer cloud-based solution.</p><p>Now, continuous integration is clear (I hope so) we can move to Continuous Deployment.</p><p><strong><em>Continuous Deployment (CD)</em></strong> is a strategy for software releases and CI is a building block of this process.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/1*q-QOUOELKhjJ9HOXkd7ybA.png" /></figure><h4>How it works?</h4><ol><li>Developers check the code locally and commit changes to the repository.</li><li>Repository sends a request (web-hook) to CI system</li><li>CI server runs job, which will generate a build and run tests to ensure your code works as expected.</li><li>Finally deploy the APK file to production(Google Play Store)</li></ol><p>This is how the process roughly looks like:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/657/1*GNg2beRdxjzYD8UUhKj1Iw.png" /></figure><p><strong><em>Sounds good? Awesome. Let’s do this…</em></strong></p><p>A good build process makes everyone’s lives easier. As an example we will use the following services for our build and distribution process.</p><p><strong>Services Used:</strong></p><p>Source control : <strong><em>GitLab</em></strong><br>CI server : <strong><em>Jenkins</em></strong><br>Build distribution : <strong><em>Beta by Fabric</em></strong></p><blockquote>Gitlab + Jenkins + Fabric Beta = Awesome!!</blockquote><p>For the automation process of a traditional Android workflow, we’ll use the above mentioned services and glue them together. But before we go there, we need to take them one by one, and see what they do.</p><p><strong>GitLab:</strong></p><p>GitLab is a git hosting solution with a very large toolset. It is completely free for unlimited users, unlimited private repositories, and full access to most of the awesome features they provide.</p><p><strong>Jenkins:</strong></p><p>Jenkins is an open source automation server, more specifically a continuous integration server. Jenkins is the longtime ruler of the CI/CD space. It provides hundreds of plugins to support building, deploying and automating any project.</p><p><strong>Beta by Fabric:</strong></p><p>Fabric Beta is the App distribution tool. The distribution process is much easier than other services. Also It provides a nice UI dashboard to manage the builds and invite the users/testers.</p><p>All we need to do is add an email address of the user in the Fabric account for a project and they will get an Email notification whenever the developer creates a new build.</p><p><strong>Steps for an awesome build process:</strong></p><p>1. <a href="https://medium.com/@jaisonfdo/how-to-setup-ci-cd-for-android-part-2-d67549c8fba1">Setup Jenkins server &amp; Gitlab</a><br> 2. Android Build Configuration &amp; Automation<br> 3. Distribute builds with release notes to test users via Fabric Beta<br> 4. Automated Deployment</p><p><strong>What’s next?</strong></p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fgiphy.com%2Fembed%2F3og0ICZh82LEsNjHoc%2Ftwitter%2Fiframe&amp;display_name=Giphy&amp;url=https%3A%2F%2Fmedia.giphy.com%2Fmedia%2F3og0ICZh82LEsNjHoc%2Fgiphy.gif&amp;image=https%3A%2F%2Fi.giphy.com%2Fmedia%2F3og0ICZh82LEsNjHoc%2Fgiphy.gif&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=giphy" width="435" height="244" frameborder="0" scrolling="no"><a href="https://medium.com/media/436858f273754c04d322c2174faa83a5/href">https://medium.com/media/436858f273754c04d322c2174faa83a5/href</a></iframe><p>In the next part of this <a href="https://medium.com/@jaisonfdo/how-to-setup-ci-cd-for-android-part-2-d67549c8fba1">post</a>, we will be focusing on the Jenkins server setup and the Gitlab setup for this automation process.</p><p>Enjoyed the story? Leave some claps 👏 here on Medium and share it with your friends. Want to stay up-to-date on the latest in Android app dev? Follow me on Twitter. I won’t spam your feed. 😄</p><p><a href="https://twitter.com/jaisonfdo">Jaison Fernando (@jaisonfdo) | Twitter</a></p><p>Check all the top articles at <a href="http://droidmentor.com/">http://droidmentor.com/</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=acb390a6aa3f" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>