Adding React Native to an existing Android App

After my recent adventures with ReactJS, I have been thinking of playing around a bit with React Native. I have looked at it before and even gave a talk on a previous version of it at a previous AndroidPhilly event.  Instead of trying a new React Native app, I figured it might be a good idea to maybe try it on an Android app I am already developing (more on that later). Instagram recently wrote an interesting article on adding React Native to their existing app so I was glad there was a migration path for native apps that didn’t involve starting a React Native app from scratch.

Let go

laptop

The React Native site has a fairly good walkthrough on adding RN to a native app. I did as instructed (I think) and mostly things went ok. And then, the expected issues began.

So long Jack

Hitting compile on AndroidStudio seemed to work for a bit and then it would just hang. Not getting anything useful there, I tried to compile the app from the command line using

./gradlew installDebug

What I saw was that the process would get stuck at a compile with Jack process. Jack was a new toolchain Google was building for Android development and I was the way to use some Java 8 features on current devices. However this month Google announced they were moving away from Jack and fortunately, my app barely used it. So I decided to remove Jack from the app altogether. That worked and AndroidStudio compiled and packaged the app and I got my app running on the emulator! It looked like…

js

Wherefore art the JS Bundle

This seemed to be an simple network issue with the emulator not seeing the locally running server. Having dealt with this while trying to get the emulator to see a locally running rails api, I figured it was something simple. React Native comes with a build it settings activity that you can call by rage-shaking the device or executing

adb shell input keyevent 82

which brings up the options menu that you can then use to launch the Settings Activity.

Wrong Settings

…except that doing that launched my apps preferences screen. Turns out React Native was just looking for a file named preferences.xml file and launching that. It just happens my app’s preferences screen was also defined by the xml file with the same name and so there was a conflict. Changing my apps preference.xml file name got around that.

Crash

I changed the ip address on React Native’s debug screen and went back to the main activity only to have the app crash. Looking at Logcat, I got this weird error

Caused by: java.lang.IllegalAccessError: 
Method 'void android.support.v4.net.ConnectivityManagerCompat.()' 
is inaccessible to class 'com.facebook.react.modules.netinfo.NetInfoModule' 
(declaration of 'com.facebook.react.modules.netinfo.NetInfoModule' 
appears in /data/app/*****.debug-2/base.apk)
     at com.facebook.react.modules.netinfo.NetInfoModule.(NetInfoModule.java:55)
     at com.facebook.react.shell.MainReactPackage.createNativeModules(MainReactPackage.java:67)
     at com.facebook.react.ReactInstanceManagerImpl.processPackage(ReactInstanceManagerImpl.java:793)
     at com.facebook.react.ReactInstanceManagerImpl.createReactContext(ReactInstanceManagerImpl.java:730)
     at com.facebook.react.ReactInstanceManagerImpl.access$600(ReactInstanceManagerImpl.java:91)
     at com.facebook.react.ReactInstanceManagerImpl$ReactContextInitAsyncTask.doInBackground(ReactInstanceManagerImpl.java:184)

Oh weird. Going by this thread, it looked like an API change in Play Services recently was causing an issue. But hold on, according to the conversation, the issue was fixed in RN v22. What the heck was I using?

Listing dependencies with gradlew

I didn’t know this but you can actually list your exact dependency tree by calling

./gradlew app:dependencies

which gives you a nice dependency tree that looks like

Screen Shot 2017-03-29 at 1.05.06 AM

Since the dependency stated in my build.gradle was just

compile "com.facebook.react:react-native:+"

it could be satisfied by any instance of RN gradle found on Maven Central. Except that one of the steps in setting up the project included defining the local folder in node_modules that held the latest (0.43 at the time of writing) and the only version on Maven Central was old (0.20). Turns out (after about an hour of pulling my hair out) that there was an error in the file path I had used to identify the node_module location and setting it right fixed the final issue.

Viola!

4 hours of dev or so and my app finally launched its hello world React Native screen alongside the native activities. Not too bad, I was expecting worse, given all the new tools in play. Lets hope this is worth it.


Tip:

Btw, unlike developing React for the web (using CreateReactApp), the console that you use to launch the dev server does not show the log messages. To see your app logs, use

reactnative logandroid

 

Presentation: Introduction to React Native for Android

Last week I gave a quick presentation at Android Alliance Philly on React Native, Facebook’s new framework that lets you develop native mobile apps using JavaScript and JSX, a layout language modeled after HTML and CSS. The deck is embedded below:

All source code for the example project can be found on Github

Thanks to all who came out to the event.

UI Concept: Using Android’s Soft Keys for Screen Pinning

I have written before on how Android could be using their software navigation buttons more appropriately. Seeing how Android 5.0 and 5.1 handle screen pinning seems another one of those situations where it could leverage that capability.

For those unaware of the feature, Android 5.0 introduced a feature that allowed you to pin a certain application to the home screen. The primary use case for this feature is to prevent a child or some one you hand over your phone to to accidentally exit an app that you want them to see/use. Since the feature doesn’t require a pin number to exit the app, the feature is not so much designed for security but rather for preventing accidents. Exiting the pinned app requires you to tap the “Back” and the “Overview” screen at the same time. A feature that people may forget (though the OS does bring up a message if you do tap any of the navigation buttons when a screen is pinned). This is probably what prompted a more explicit how-to view explaining the exit action in Android 5.1.

However this feature once again doesn’t take into account the Android soft keys. When a screen is pinned, why not change the graphics for Back and Overview to pin icons. This would also reinforce the fact that the phone is in a separate “pinned screen” mode.

screen-pin

As always, thoughts are welcome 🙂

Announcing Artbook: An Android Client for Dribbble

I am a big fan of Dribbble. For the uninitiated, its a community for designers to share parts of their work and is pretty inspirational when you are thinking of designs for your own applications. When I released FreeFlow earlier this year, I included a sample Dribbble project as part of the release to showcase the power of layout system. Since then I recieved a couple of messages from a few folks to just complete that as an app since a lot of the work was already done anyway. It also didn’t seem like there were any really compelling Dribbbble apps on the Play Store (well none that I felt were very interesting anyway). So last week I worked a bit and finished the Artbook app

Like the original source that was included in FreeFlow, Artbook is completely open source and released under the Apache 2 license. The code for the app has some ugly parts but is generally okay. Having recently acquired a 10.1” Android tablet (the Galaxy Note 10.1 mostly for drawing), I really wanted to make sure it had a fantastic tablet experience. However unlike Google’s direction to use Fragments for multi device layouts, this app does it via just a few simple if-else blocks and conditionally loading layouts. I find this approach so much simpler than any elaborate Fragment based architectures.

Anyway, I hope you give it a shot and see if you like it. I find browsing Dribbble a lot more fun using it

 

Improving Android’s NavigationBar

One of the interesting features that were released as part of Android 3.0 HoneyComb release back in 2011 was the introduction to the soft navigation buttons. To me, the system seemed full of potential as navigation buttons adapted to better educate the user as the user used the system. For example, while using an application, if the user ended up launching the keyboard, the back button would change to indicate that back would now just dismiss the keyboard and not actually go back to the previous screen.

keyboard

 

Three years later, I am surprised that not much else was added. The back navigation while powerful still can get ambiguous at times. Below are a couple of ideas I think can really improve the user experience on Android today.

Preventing accidental over-backing

Accidentally hitting back one too many times is a problem that I encounter enough times that it really does get irritating. I am sure it happens to other app developers as well, which is why often you see developers implementing the extremely frowned upon “Are you sure you want to exit” modal alert in apps.

The soft button could really fix this problem by changing itself to indicate that you are at the last item in a stack. I am not an icon designer but here is how I imagine the soft keys changing when the user is on the only activity in the stack. The icon clarifies that hitting that button will exit the activity.

app-close

 

 

Enabling Done Discard Pattern

The constant presence of a back button causes confusion in one other place: when a user is modifying data, like adding a todo item on a list or adding a new contact. Without an explicit tap on a save button, hitting back or tapping on the Home icon now adds ambiguity to the question of whether the user wanted to save the data or not. One of the nicer patterns that emerged in Android was the Done/Discard pattern that Roman Nurik released as an Android library a while back, but because it doesn’t prevent the back button, a better way was if Android introduced a “Done Discard Activity” that would modify the back button and maybe temporarily hide the multitasking action.

done-discard

 

What do you think? How else could the the digital nature of the Android navigation bar be used to improve Android UX?

Big in China

I haven’t looked at the usage stats for PicScribe in a while. It does the couple of things I need it for and I am mostly content with the functionality. But with Material Design I was thinking of giving the app a refresh as well as add some features I had been meaning to as well.

Looking at the stats today was interesting though. Looking at my integrated Google Analytics data, it appears that majority of the app usage is happening in China where Google Play doesn’t even exist. I have no idea how they got the app, its free so it doesn’t matter, but still.

china.png
All the top phones are also local ones (mostly Xiaomi ).

Lesson of the day: Make sure you add analytics to your app.

 

 

 

Android wishlist: A different notification UI for background services

This post is first in a series around enhancements to the mobile experience I’d like to see going forward. Stay tuned for more 🙂

Background services are one of my favorite features on Android. As the idea of a smartphone changes from a phone to a true contextual device, background services that keep track of user context and push information to the user at appropriate times are essential. That said, the current visual treatment they get on the device to let a user know that they are running, which hasn’t changed much since the inception of Android, needs to change.

The Problem

Here is a screenshot of my notification shade right now. Note that only one of the 8 notifications I am currently seeing is actually a new event that I actually need to respond to. The flooding of my notification window with the always running service notifications numbs me to actually important actionable notification that sits there.

2014-05-10 12.59.31

 

Proposed Solution Option 1:  Notification Tabs with services tucked away

A lot of ROMs already implement Notification Tabs. Moving the background services to a separate tab so that I don’t have to look at them whenever I pull down the shade would solve the problem, though it does add some complexity to the shade.

2014-05-10 12.45.32

 

 

Proposed Solution Option 2: Collapse background service notifications into one low-priority notification:

This option may be a little better since you don’t add the cognitive complexity to the notifications shade. Simple is better usually 🙂

2014-05-10 13.35.20

Final thoughts:

In both the cases above developers will have to explicitly change their own notification priority to escape the “grouping”. So if a significant event occurs, their notification can be shown along with the rest of the notifications.

As notifications become increasingly more important to the mobile experience, like the coming smart watches that are all about contextual notifications sent by your phone, there is a greater need to make sure that we don’t overwhelm the user with an unorganized stream of information.

As always, feedback is most welcome 🙂

 

Setting up a continuous build environment for Android with AWS, Jenkins and Github

__jenkins

I have been getting more into Android testing lately, especially for a core library that we use within our team that may be shared across projects and may have different developers modifying it to suit there own needs. Not making sure that every commit doesn’t break the code for someone is a recipe for trouble (and I have been there). To avoid that as much as we can, last week I set up an continuous build environment that can run tests against the core library on every commit.

The parts:

  • AWS: There are a bunch of advantages of using AWS, but the biggest advantage is the availability of preconfigured stacks called AMIs that can be deployed immediately on an EC2 instance.
  • Jenkins: Jenkins is a pretty popular continuous integration server. Jenkins is deployed as a Java War Its used at other parts of the company too so I can seek help if I get into trouble.
  • Github: Github is a very popular code hosting service. We have been using it for a bit and its been very convenient for code that needs to be shared or open sourced.

Steps:

  • Select the Bitnami AMI from the AWS marketplace and deploy it on a new EC2 instance
    • The AMI creates a couple of users on the server: A default “bitnami” user and another “tomcat” user thats actually starts up a Tomcat server thats has the Jenkins app deployed.
    • The Bitnami AMI has also created a user named “user” with password “bitnami” that you can use to log in to Jenkins. You can at this point decide how you want new users to be added to the system and who has access permissions.
    • If the deploy works, you should be able to go to the root of your server and see a link to the running instance.
  • On the left nav, click on Configure link to set up global configuration for your install
  • Under Manage Jenkins  >  Configure System
    • Make sure Ant is set up to download if needed
    • For Android make sure “Automatically install Android if needed” is checkedScreen Shot 2014-01-05 at 5.52.36 PM
  • Create a new Job and choose “Build a free-style software project” 
  • In the configure tab, under the Source Code Management section, choose Git and paste the Github URL for the project.
    • Note this part is a little buggy. The problem that took me way too long to realize is that the Tomcat user doesn’t have Github.com in its list of known hosts. Follow the steps here to fix that.
  • On the server, as the Tomcat user, create your ssh keys that you will use to authenticate your pull requests with Github. See Github’s guide for doing that here
  • Add the public key in the account for an authorized Github user (May not be a bad idea to create a new Github user just for build purposes)
  • Log in to your Jenkins account on the web again and in add your private key against the user account in the user settings section. Conveniently, Jenkins can read ssh keys from the running server but you may need to enable that.
  • At this point the system is pretty set up. Now make sure your Android project is set up for testing by following the guide on the Android Developers site. At the end you should have 2 projects: Your main application and a test application. Both will have Ant based build.xml files that you will have Ant on Jenkins run. Commit your projects to Github.
  • You can point to the build.xml
    file you want to execute. If there is a build.xml
    at the root of the project that’ll be executed by default.
  • You should now be able to build your project explicitly at least. Go to your “Job” and click build now.
  • You can then set up automatic builds by going into your project settings on Github and go to > Service Hooks > Jenkins (Git Plugin) and pointing it to your server url.
    Screen Shot 2014-01-05 at 6.25.49 PM

Thats it. Now every time a developer pushes to Github, Github will notify Jenkins, which will pull your repo and run the appropriate build file.

Continue reading “Setting up a continuous build environment for Android with AWS, Jenkins and Github”

Android: Implementing Touch Feedback on Views

One of the most commonly overlooked parts of building Android applications is touch feedback. While some views like Buttons have touch feedback built into them, thats not the case when using custom views.

The Android Design Guidelines explicitly talk about the UX part of touch feedback and it was also discussed a while back on the Android Design In Action YouTube series:

The problem is that there are no clean standard hooks in the Android framework to implement these. The only implementations I have found have been:

  • FrameLayouts have a foreground property that can be used
  • ViewGroups like the ListView that extend the AbsListView class have a property called “drawSelectorOnTop” that can be used to draw the background selector on top of your custom item renderer.

Given the lack of default apis in most of the common layouts, one approach that you jump to (like I did) was to listen to touch events and change background on touch down  and up. This is hard to implement perfectly because a touch event can be canceled in a bunch of ways. For example, a user may be swiping across your view and you may still end up showing touch feedback which would be wrong. In our app, we often ended up with views stuck in an incorrect state.

The Android framework’s selector system (or rather the StateListDrawable class) handles a bunch of these situations appropriately already. The best approach therefore is to create a selector and the apply that to your view. Setting that selector as your view’s background though will draw that under all the views on top which doesn’t work either. To fix that, the best approach is overriding the dispatchDraw method and then after calling super, calling your new drawable’s draw method within the bounds of the View, something like:

@Override
protected void dispatchDraw(Canvas canvas){
super.dispatchDraw(canvas);
touchFeedbackDrawable.setBounds(0,0,getWidth(), getHeight());
touchFeedbackDrawable.draw(canvas);
}

The one gotcha here is that the base ViewGroup does not invalidate custom drawable invalidated automatically, so this is something you have to do by overriding a different method:

@Override
protected void drawableStateChanged() {
if (touchFeedbackDrawable != null) {
touchFeedbackDrawable.setState(getDrawableState());
invalidate();
}
super.drawableStateChanged();
}

Props to Rich Ratmansky for solving this quirk.

The final result looks something like this:

touch_feedback

I have created a sample project to show the experience. You can find the project on Github. This works well, but as you can see it does require a custom ViewGroup class. If anyone from the Android framework team is reading this, having a “touchFeedbackDrawable” property would probably be really useful extension to the framework.

[Update] Had an interesting discussion on this on Google+, whether touch feedback should be shown in a view’s background or foreground. The consensus seems to be background as long as the background is fairly prominent/visible. For opaque content like say images, foreground feedback is pretty much required.