Showing posts with label Android. Show all posts
Showing posts with label Android. Show all posts

Tuesday, August 29, 2017

Android services

Android Services

What is a service?



Normally, when trying to execute an operation in Android it is, in some way, related and linked to a user interface. However, sometimes it would be better to run some long operations on the background, and just notify the user at the end. Or maybe just keep something running all the time, such as a music player. For these cases we can use a Service.


A service is a component which runs in the background without a user interface. Services will continue running even if the user changes to another application, ensuring the long operations are not interrupted by mistake.


There are many kinds of services at our disposal on android, so let’s see what are the main differences.


Services types



Started service



This is the basic type of service. It is usually used to perform a single operation, without returning a final result to the caller. It is created when “startService” is called for the first time and will be destroyed when “stopService” is executed. While “startService” can be called many times while the service is still running (and it will execute the “onStartCommand” function every time), it will not be re-created and will be destroyed when the “stopService” is ran for the first time. It does not matter how many times “startService” is called, it will end when “stopService” is executed once.


Started services can either be Sticky or not Sticky. The difference between a sticky and a not sticky service is what happens when the system kills the service. If the service is not a sticky service, it will not be recreated unless there are pending intents to be delivered. Meanwhile, a sticky service will be recreated regardless of if there are pending intents or not. In case there are none, it will be recreated with a null intent.


Not sticky services should be used when the it is possible to re-start the operation if unfinished and necessary, so the system can manage it appropriately. If it is vital that the service keeps running until stopped manually, you can use a sticky service.


There is also a started service called “redeliver intent”, which is useful when doing long operations that shouldn’t be interrupted. In this type of service, when the system kills it it will be re-created using the last intent that was delivered, and will use the pending intents subsequently. This allows for operations to be continued with the same intent instead of cancelling them altogether.


Bound service



Another type of service is the bound service. In this, instead of calling “startService”, when an activity wants to use this service it “binds” to it. The service is created when the first bind is made, and it continues running. This service can be binded to multiple times by different activities. When this service is binded to it returns an object that implements the “IBinder” interface to be used.


When the service is no longer required by an activity that is binded to it, the activity should call “unbind” to that service. After all activities which were bound to the service call “unbind” (meaning there are no more activities binded to this service), the service is destroyed.


Note: Bound Started service



It is possible to have a service that is both bound and started. This can be useful for some really specific situations but it is not commonly used and it normally leads to more confusion and problems than it is worth. Consider if this is exactly what you want before using it.


Scheduled service



A scheduled service is basically what the name suggests. It is a service that is scheduled to run at a later time. This can be done by using the JobScheduler class, and it allows you to set when to run this service, and even conditions to see if the service should be executed or not depending on status of the device when the scheduled time is reached.


Life cycle



A service follows a simple life cycle during its use. This lifecycle is used in both started services and bound services, although they have some differences in the middle. However, the general concept is the same.


First, the service is created. This is done by calling “startService” or “bindService” depending on the type of service. At this point is when it calls the “onCreate” function which can be used for initial setup on either type of service.


Immediately after creation, it starts executing the “onStartCommand” or “onBind” function (dependin on the case). Here is where the main processing of the service is executed and where it will continue until the service is stopped. In case of bound services, “onBind” will be called every time a new activity binds itself to the service, and “onUnbind” will be called when any activity unbinds itself.


When the service is stopped (either by calling “stopService” or the last “unbind”), the function “onDestroy” is called. Finall, the service is shut down and the life cycle comes to an end.


Creating a service



Now let’s see how to actually create a service. For this exampl, we will create a started service, but creating a bound service is not really that different.


To create a service you need to create a new class that extends from “Service”. This will force us to override the method “onBind”, which is for bound services. Since we will now create a simple started service, we can return null here and move on.


Now we can implement the methods we wish. As explained earlier, we can implement “onCreate”, “onStartCommand”, or “onDestroy” depending on what we need. There are others that we could implement but those are not important for this basic tutorial. The one that we should implement to actually have a started service as we want is the “onStartCommand” one. Here is also where we can choose which type of started service we want to create. This is determined by what we return at the end. Return either “START_NOT_STICKY”, “START_STICKY”, or “START_REDELIVER_INTENT”, depending on what you wish to do.


Here you can see the code for creating a started not sticky service:

package com.servicesexample.innuy.servicesexample; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.support.annotation.Nullable; import android.widget.Toast; /** * Created by Innuy. */ public class ExampleService extends Service { @Nullable @Override public IBinder onBind(Intent intent) { return null; } @Override public int onStartCommand(Intent intent, int flags, int startId) { Toast.makeText(this, "Here the service is started", Toast.LENGTH_LONG).show(); return START_NOT_STICKY; } }
What we need to do now is add our new service to the Android manifest. Just add the following line changing the name of the service to yours:


<service android:name=".ExampleService"></service>
The last step is to call this service. For this you just need to create an appropriate intent and call “startService” from an activity as it is shown in the code below:

startService(new Intent(getBaseContext(), ExampleService.class));
And there it goes! If you use the above code you will see the Toast being shown whenever you start the service. To stop this service just call “endService” with an intent of the same service.


Sources

Services Documentation - Android Developers https://developer.android.com/guide/components/services.html


Secondary links:


Wednesday, August 2, 2017

Ionic - Secure Storage


This post is not meant as a guide nor as a tutorial on how to use storage with Ionic. This post will explain a possible problem you may have when using the Secure Storage plugin as described in Ionic docs. Also, this is a problem that only shows itself on Android and not on iOS, so if you are facing issues on an Apple device this is probably not the problem you are encountering.

‘Native Storage’ and ‘Secure Storage’ plugins



Native Storage and Secure Storage are the two main ways for you to store information on mobile with Ionic, without needing to set up your own database and instead delegating the handling to the OS.


As the name suggests, the latter is normally used when the information to be saved is really sensitive.


This doesn’t mean Native Storage by itself is insecure. Data stored in this way should only be accessible by your app, which leaves it pretty safe in its own right. However, it is still possible to access it if the backup of the data is enabled or on an Android device if it is rooted. So, for cases in which security is a top priority, Secure Storage can shine.


But, when using the “Secure Storage” plugin on Android, sometimes it may fail when starting or when using it. It may even delete previously stored information. So now we have to make the decision on which one to use. Before that, however, it would be good to know why this happens, and how often it happens.


Secure Storage on Android



The “Secure Storage” plugin on Android only works correctly when the user has a block screen activated for their device. Be it with a pattern or with a code, the plugin uses the KeyStore associated with the lock to encrypt the data to be safely stored.


What this means for a user using our application with secure storage, is that it will only work if the device has this safety measures in place. If they don’t, the plugin will fail to initialize, and all storage or retrieval operations will subsequently fail.


And this is not the worst case scenario. The worst case scenario comes when the user removes or updates their password or pattern. If this happens, all previously stored information will be basically deleted since the key associated with it will change.


iOS, on the other hand, doesn’t have this problem since it uses KeyChain to store the information with this plugin, and this does not depend on the user actually having security enabled for their device.


Solutions



Now we need to make a decision on what to use, and the answer should change depending on what your App needs. Some options would be the following:


  • If the data to be stored is not sensitive enough, just use Native Storage. It is secure enough for many cases since it needs a special scenario to be compromised.
  • If data is really sensible, and its use can be avoided, you can use Secure Storage. You need to check before using it in case it was deleted, but this will ensure everything is secure.
  • If data is sensible but temporary (as a short session token) you can try using both. Start by using Secure Storage and just default to Native Storage when that fails. This will allow most users to have the full security without annoying the other users. You can also try migrating data from Native Storage to Secure Storage if it is detected through the App that the user activated their screen lock security.
  • If data is sensible, you could also use Secure Storage and actively ask the user to enable screen lock. This will make sure your data is safe and that your app can access it (unless the user later disables it), but it may annoy the user. You also need to check for possible disappearance of data in every storage operation.
  • You could also choose to use neither. You can try using your own database and handle its security on your own. This can be done either mobile or server side, depending on your needs, but remember that this will probably be more time consuming than just using one of the other plugins.

Conclusion



Unluckily there is not a definitive solution to your problem, but it is something important to have in mind when using these plugins. You just need to make sure you know the needs of your app, your users and the information to be stored and make an informed decision.

We hope this quick post was useful to you!




Sources

Thursday, July 27, 2017

React Native: Using native code



In this tutorial, we will assume some basic knowledge of Swift and Java, but it is not necessary to follow along.


In my last post, we started with React Native, creating our first project and understanding the basic structure. However, we didn’t get into one of the best features of React Native: being able to easily write native code to get access to native features or simply upgrading the performance.


So we will try writing a small app which will take advantage of native code to add a new contact to the phone on either iOS or Android.

Let’s get started!

Updating from previous code (Ejecting)



First, let’s get a bad part out of the way. We can’t use native code directly if we created our app with “create-react-native-app”, at least not immediately. And that is exactly what we did in the last tutorial. However, this is easy to fix, so don’t worry! We just need to eject our previously created project and we will be good to go.


To eject your project, you will need to have react-native-cli installed, so just run the following command:
yarn global add react-native-cli
#Alternatively you could install this with npm instead if you wish with npm i -g react-native-cli

Once react-native-cli is installed, navigate to your project and run the following command to eject:
npm run eject
You will be prompted to answer some questions to guide the eject process. For this tutorial, we will choose a regular React Native project, and we will use “ContactsProject” as the name for the project.


Lastly just delete the node_modules folder and run “yarn install” and we will be all ready to continue.


One final word about ejecting your project. After doing this you won’t be able to use the QR code as explained in the other post for running the application. Instead, you will need to launch it from the console or from XCode / Android Studio. But this shouldn’t be too much of a deal while continuing your own project.

Connecting with native code



Now that we have our project ready, we can start focusing on the native part. For this tutorial, we will start with a fresh projected as created by create-react-native-app, and ejected as described above.

Connecting with iOS (Swift)



First, we will start by creating a new swift file (we will call it “ContactsManager.swift”) in your project folder that it’s inside the “ios” folder. It is recommended this is done with XCode since you will be immediately prompted to create a bridging header file (“ProjectName-Bridging-Header.h”), which we will need. If you don’t do it this way it can be added later, so don’t worry.

Inside “ContactsManager.swift” let’s add the following code:


import Foundation
import Contacts
@objc(ContactsManager)
class ContactsManager: NSObject {
 
}
We just created a new class called “ContactsManager” which will be where the logic for adding the contact will be done later. One thing to note is the “objc” modifier. React Native will communicate with Objective-C, so this is an extra step to pass Swift code to Objective-C. If you feel more comfortable with Objective-C you can code directly in Objective-C and skip this, but in this tutorial, we will continue with Swift.


Let’s add now add our function to add the new contact. I won’t go into how exactly this function works since we should concentrate more on linking the code than the adding of the contact, but it should be self-explanatory.


Add the following code inside that class:


@objc(addContact:familyName:number:)
 func addContact(name: NSString, familyName: NSString, number: NSString) -> Void {
   
   if #available(iOS 9.0, *) {
     let contact = CNMutableContact()
     
     contact.givenName = name as String
     contact.familyName = familyName as String
     
     contact.phoneNumbers = [CNLabeledValue(
       label:CNLabelPhoneNumberiPhone,
       value:CNPhoneNumber(stringValue:number as String))]
     
     // Saving the newly created contact
     let store = CNContactStore()
     let saveRequest = CNSaveRequest()
     saveRequest.add(contact, toContainerWithIdentifier:nil)
     try! store.execute(saveRequest)
     
   }
 }
We need to use “objc” in the function too. As you can see, the function itself is the same as how we would do it natively. Nothing too complex here.


Now we have all the native code that we would like to run in our React Native app, but how to do it? Well, first we need to indicate the classes and functions we would like to be accessed externally in the JavaScript. For this we will need a bridge file (“ContactsManagerBridge.m”) as follows:


#import <React/RCTBridgeModule.h>
@interface RCT_EXTERN_MODULE(ContactsManager, NSObject)
RCT_EXTERN_METHOD(addContact:(NSString *)name familyName:(NSString *)familyName number:(NSString *)number)

@end
In this, we indicate the class, the methods and the parameters that will be used by our JavaScript code.


The last piece of native code we need is in the bridging header which we created at the start of this section. In that file you just need to indicate that you will be using the Bridge module with this line:


#import <React/RCTBridgeModule.h>
And we are finished with the iOS part. Depending on the version of iOS you are using you may need to modify the .plist to include permission text for using Contact, but that should be easy to fix.


So let’s return to our “App.js” where the application will start. Here, we can use the following code:



import React from 'react';
import { StyleSheet, Button, View } from 'react-native';
import { NativeModules } from 'react-native';
export default class App extends React.Component {
render() {
  return (
    <View style={styles.container}>
        <Button onPress={addContact} title="Add contact"/>
    </View>
  );
}
}
function addContact(){
  let ContactsManager = NativeModules.ContactsManager;
  ContactsManager.addContact('John', 'Doe', '(555) 424-5920');
}
const styles = StyleSheet.create({
container: {
  flex: 1,
  backgroundColor: '#fff',
  alignItems: 'center',
  justifyContent: 'center',
},
});

As you can see, this will just display a simple screen with just one button, and when that button is pressed it will call the “addContact” function. This function is what calls the native code we have been implementing until now. It brings “ContactsManager” from the native modules and calls the function we created before.


And now you are ready! Just run this project, which you can easily do from XCode, and you will see the App. After clicking the button in the middle of the App, a new contact called “John Doe” should be added to the Contacts on your phone.


Connecting with Android (Java)



First, we will start by creating a new Java file in your android project folder (we will call it “ContactsManager.java”). This is where we will write our Java code to be executed by our application.


For our example, we will create a simple class called “ContactsManager”, which will extend ReactContextBaseJavaModule. This allows us to later export this class as a native module to our React Native JavaScript. This class should also override the “getName” method, returning the name by which we will access this module on the JavaScript, as it is shown in the following code:



public class ContactsManager extends ReactContextBaseJavaModule { public ContactsManager(ReactApplicationContext reactContext) { super(reactContext); } @Override public String getName() { return "ContactsManager"; } }


Now we can add our method that we wish to call from the JavaScript. This is done exactly as we would for a native android app. The only difference is that we need to add “@ReactMethod” before the declaration.


Just add the following code to the Java file:


@ReactMethod public void addContact(String firstName, String lastName, String phoneNumber) { Context contetx = getReactApplicationContext(); String strDisplayName = firstName + " " + lastName; String strNumber = phoneNumber; ArrayList<ContentProviderOperation> cntProOper = new ArrayList<ContentProviderOperation>(); int contactIndex = cntProOper.size(); cntProOper.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI) .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null) .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null).build()); cntProOper.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID,contactIndex) .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE) .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, strDisplayName) .build()); cntProOper.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID,contactIndex) .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE) .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, strNumber) .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE).build()); try { ContentProviderResult[] contentProresult = null; contentProresult = contetx.getContentResolver().applyBatch(ContactsContract.AUTHORITY, cntProOper); } catch (Exception exp) { }
}
Since we have finished with preparing the module we need to work on exporting it. For this, we will create a new file (we will call it “ContactsPackage.java”) where we will package modules to be later used in our React Native app. In this, we will create a new class which implements “ReactPackage”. We could add many modules in one package, but for this example, just the one we created before is enough.


Add the following code to the new package file:


public class ContactsPackage implements ReactPackage{ @Override public List<Class<? extends JavaScriptModule>> createJSModules() { return Collections.emptyList(); } @Override public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) { return Collections.emptyList(); } @Override public List<NativeModule> createNativeModules( ReactApplicationContext reactContext) { List<NativeModule> modules = new ArrayList<>(); modules.add(new ContactsManager(reactContext)); return modules; } }
Lastly, we need to indicate that this package should be used in our React Native app. For this, we need to open the MainApplication.java file and add our package to the “getPackages” function. The code below shows how this would be done:


@Override protected List<ReactPackage> getPackages() { return Arrays.<ReactPackage>asList( new MainReactPackage(), new ContactsPackage() ); }
With this, we have finished doing everything on the Java side to export and use our custom native module. For this particular example, you should also add the following permission to your AndroidManifest, but this is obviously not needed for other purposes:


<uses-permission android:name="android.permission.WRITE_CONTACTS"/>
So let’s return to our “App.js” where the application will start. Here, we can use the following code:

import React from 'react';
import { StyleSheet, Button, View } from 'react-native';
import { NativeModules } from 'react-native';
export default class App extends React.Component {
render() {
  return (
    <View style={styles.container}>
        <Button onPress={addContact} title="Add contact"/>
    </View>
  );
}
}
function addContact(){
  let ContactsManager = NativeModules.ContactsManager;
  ContactsManager.addContact('John', 'Doe', '(555) 424-5920');
}
const styles = StyleSheet.create({
container: {
  flex: 1,
  backgroundColor: '#fff',
  alignItems: 'center',
  justifyContent: 'center',
},
});
As you can see, this will just display a simple screen with just one button, and when that button is pressed it will call the “addContact” function. This function is what calls the native code we have been implementing until now. It brings “ContactsManager” from the native modules and calls the function we created before.


And now you are ready! Just run this project, which you can easily do from XCode, and you will see the App. After clicking the button in the middle of the App, a new contact called “John Doe” should be added to the Contacts on your phone.


Conclusion



As you can see, incorporating native code into your React Native application is not too complicated. You can write your native code as you normally would and just do some minor bridging inside the project to indicate which functionalities should be called from where.


You may also note (if you followed both the Android and iOS sections) that we have named the module the same in both cases. React Native plays nice enough to know exactly which module to use depending on where the code is running, so you don’t even need to handle the different use for the different platforms.
If you wish to see the example code in more detail, feel free to check our github project.