<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Sérgio Santos</title>
    <description>The latest articles on DEV Community by Sérgio Santos (@sdsantos).</description>
    <link>https://dev.to/sdsantos</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F201423%2F5165f24d-ba10-426f-b962-e141e38fbe0a.jpeg</url>
      <title>DEV Community: Sérgio Santos</title>
      <link>https://dev.to/sdsantos</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sdsantos"/>
    <language>en</language>
    <item>
      <title>Envelop Browser Extension</title>
      <dc:creator>Sérgio Santos</dc:creator>
      <pubDate>Mon, 23 Dec 2019 15:54:24 +0000</pubDate>
      <link>https://dev.to/bloco/envelop-browser-extension-g3g</link>
      <guid>https://dev.to/bloco/envelop-browser-extension-g3g</guid>
      <description>&lt;p&gt;We launched &lt;a href="https://envelop.app" rel="noopener noreferrer"&gt;Envelop&lt;/a&gt; for Web and Android last June. Since then, we had around 1000 people trying it out. And it reached 10th place in the &lt;a href="https://app.co/mining/july-2019" rel="noopener noreferrer"&gt;App Mining Ranking&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Going forward, our main goal is to keep Envelop as simple to use as possible. The app should not get in the way of the task you’re doing. Uploading a private file should be quick, safe and not interrupt your flow.&lt;/p&gt;

&lt;p&gt;In Android, you can already upload a file from any app on your phone, by sharing it to the Envelop Android app. Now, on the web, we've built a browser extension, so you can share file without losing the context of what you’re doing.&lt;/p&gt;

&lt;p&gt;Here's what it looks like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fgcvcvxl92l0nc1hipogd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fgcvcvxl92l0nc1hipogd.png" alt="Screenshot 1"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fpuu8t8b02pn23icsz758.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fpuu8t8b02pn23icsz758.png" alt="Screenshot 2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Some great use cases for the Envelop browser extension:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your email client doesn’t allow you to attach files larger than 20MB&lt;/li&gt;
&lt;li&gt;Your messaging app doesn’t let you send a certain file type&lt;/li&gt;
&lt;li&gt;You’re filling in a form without a field to upload a file&lt;/li&gt;
&lt;li&gt;You can bypass those limitations by dragging the file you want to share onto the extension window and getting a link to send. Envelop ensures your files stay private and encrypted.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The browser extension supports Chrome, Firefox and Opera. Give it a try:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://chrome.google.com/webstore/detail/envelop/fedfongpkeoiknldijklbhhmiomelogi" rel="noopener noreferrer"&gt;Chrome&lt;/a&gt;&lt;br&gt;
👉 &lt;a href="https://addons.mozilla.org/en-US/firefox/addon/envelop/" rel="noopener noreferrer"&gt;Firefox&lt;/a&gt;&lt;br&gt;
👉 &lt;a href="https://addons.opera.com/en/extensions/details/envelop/" rel="noopener noreferrer"&gt;Opera&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Some details from under the hood
&lt;/h2&gt;

&lt;p&gt;We opted for a window popup, instead of dropdown under the extension icon, so we could support file drag and drop.&lt;/p&gt;

&lt;p&gt;The popup just opens a special version of the web app, designed for the small window. This has which has two advantages. It avoids needing to authenticate twice, once for the web and again for the extension. And updates are simpler, you instantly get the latest version of the app on the extension.&lt;/p&gt;

&lt;p&gt;For cross-browser support, we relied on the &lt;a href="https://developer.mozilla.org/pt-PT/docs/Mozilla/Add-ons/WebExtensions" rel="noopener noreferrer"&gt;Web Extensions APIs&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>blockstack</category>
      <category>browser</category>
      <category>webextension</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Blockstack Android Tips</title>
      <dc:creator>Sérgio Santos</dc:creator>
      <pubDate>Thu, 25 Jul 2019 11:25:44 +0000</pubDate>
      <link>https://dev.to/bloco/blockstack-android-tips-36l8</link>
      <guid>https://dev.to/bloco/blockstack-android-tips-36l8</guid>
      <description>&lt;p&gt;When developing the &lt;a href="https://play.google.com/store/apps/details?id=app.envelop"&gt;Envelop Android app&lt;/a&gt; using the &lt;a href="https://github.com/blockstack/blockstack-android"&gt;Blockstack Android library&lt;/a&gt;, I ran into some important gotchas. I wanted to share them for whoever starts on the same path.&lt;/p&gt;




&lt;h2&gt;
  
  
  Starting out
&lt;/h2&gt;

&lt;p&gt;The library is still pre-release, but it’s built upon the more stable blockstack.js library. That means is also not a native library. It uses the j2v8 engine to interpret and interact with the javascript library.&lt;/p&gt;

&lt;p&gt;The two main consequences are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your app will weight around 20Mb more due to the blockstack library&lt;/li&gt;
&lt;li&gt;You need to be careful when you initialize a &lt;code&gt;BlockstackSession&lt;/code&gt;. It takes a while for it to be ready to use.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Threading
&lt;/h2&gt;

&lt;p&gt;The library threading is configured by an &lt;code&gt;Executor&lt;/code&gt;. It defines 3 threads, the main thread, the background thread and the V8 thread that runs the javascript library.&lt;/p&gt;

&lt;p&gt;By default, the V8 thread uses the main thread. But for a production app, that means blocking the main thread on every operation, something definitely not recommended. To avoid this, you should define a new &lt;code&gt;Executor&lt;/code&gt; and set it on the &lt;code&gt;BlockstackSession&lt;/code&gt;. Here’s an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BlockstackExecutor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Context&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Executor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;handlerThread&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;HandlerThread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"BlockstackV8"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;apply&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;handler&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;handlerThread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;looper&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onV8Thread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Unit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invoke&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onMainThread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Unit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;GlobalScope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Dispatchers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Main&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onNetworkThread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;suspend&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Unit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;GlobalScope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Dispatchers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;IO&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;But now you need to make sure you’re calling the blockstack operations for the thread you just created. If, for example, you’re using RxJava, that means building a custom &lt;code&gt;Scheduler&lt;/code&gt; for that thread, and using it in &lt;code&gt;subscribeOn&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;blockstackScheduler&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Schedulers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;For example, here’s how we wrap a &lt;code&gt;deleteFile&lt;/code&gt; operation with RxJava:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;deleteFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
  &lt;span class="nc"&gt;Completable&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;emitter&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
      &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;blockstack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deleteFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;DeleteFileOptions&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hasErrors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;emitter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;emitter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onComplete&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Throwable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;emitter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribeOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;blockstackScheduler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Network Errors
&lt;/h2&gt;

&lt;p&gt;In the current library version (0.4.3), there’s a bug that hides network errors. They become indistinguishable from requests that are taking too long. There’s a &lt;a href="https://github.com/blockstack/blockstack-android/pull/153"&gt;pending PR&lt;/a&gt; to fix it. But until then, we’re using our &lt;a href="https://github.com/sdsantos/blockstack-android"&gt;own fork&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Context
&lt;/h2&gt;

&lt;p&gt;In the examples given, &lt;code&gt;BlockstackSession&lt;/code&gt; is initialized with an &lt;code&gt;Activity Context&lt;/code&gt;. But for almost all Blockstack operations, the &lt;code&gt;Application Context&lt;/code&gt;. This is useful for taking that logic out of the &lt;code&gt;Activity&lt;/code&gt; classes and properly architecture your code.&lt;/p&gt;

&lt;p&gt;But the login call &lt;code&gt;redirectUserToSignIn&lt;/code&gt; requires a &lt;code&gt;BlockstackSession&lt;/code&gt; with an &lt;code&gt;Activity Context&lt;/code&gt;. That’s because it opens a webview from the inside. If you still want to use the &lt;code&gt;Application Context&lt;/code&gt; for all the other calls, just make sure the different &lt;code&gt;BlockstackSession&lt;/code&gt; instances share the same &lt;code&gt;SessionStore&lt;/code&gt;. That way, all &lt;code&gt;BlockstackSession&lt;/code&gt; instances read and store the session data from the same location.&lt;/p&gt;

&lt;h2&gt;
  
  
  APK signing
&lt;/h2&gt;

&lt;p&gt;This one is not directly related with Blockstack, but something to keep an eye on. During login, users first sign in on Blockstack inside a webview. Then the authentication response comes back to the Android app through an app link. For that process to be seamless, the app link should be &lt;a href="https://developer.android.com/training/app-links/verify-site-associations"&gt;automatically verified&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Google Play now encourages delegating the APK signing process to them. But that means that the &lt;code&gt;sha256_cert_fingerprints&lt;/code&gt; that ends up in the server &lt;code&gt;assetlinks.json&lt;/code&gt; file will not be the one you would expect. Your upload key signing gets removed from the APK. You need to fetch the correct fingerprint from your Google Play Dashboard under &lt;code&gt;Release management &amp;gt; App signing&lt;/code&gt;.&lt;/p&gt;




&lt;p&gt;And that’s what I’ve got. Hope I didn’t scare you too much, it’s not that bad actually. Just some details that will likely be ironed out in the future. Any other issue, you can reach out on the &lt;a href="https://github.com/blockstack/blockstack-android"&gt;library’s Github&lt;/a&gt;. I’ll be keeping an eye on there too.&lt;/p&gt;

&lt;p&gt;Curious about what a Blockstack app is like? Try out our &lt;a href="https://play.google.com/store/apps/details?id=app.envelop"&gt;Envelop Android app&lt;/a&gt;, and look into our app’s &lt;a href="https://github.com/envelop-app/envelop-android"&gt;source code&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>blockstack</category>
      <category>android</category>
      <category>kotlin</category>
      <category>blockchain</category>
    </item>
  </channel>
</rss>
