Android app with NDK

Follow guidelines to setup your Android Studio. You need to download Android NDK with  “Tools” > “Android” > “SDK Manager”, then select the tab “SDK Tools” and check “Android NDK” if it is not checked.

Now while creating new project notice the checkbox for cpp/JNI compatibility in the project.

For me Android Studio was creating native-lib.cpp cpp file and also adding it to CMakeLists.txt. On compilation you will get an .so file named libnative-lib.so.

#include <jni.h>
#include <string>

extern "C" JNIEXPORT jstring JNICALL
Java_com_example_myservice_MainService_getString( JNIEnv* env,
                                                            jobject thiz )
{
    return env->NewStringUTF(" Hello from JNI !  This Worked");
}

 

I forgot extern “C” that is why I highlighted it here. In c file things are little different.

My MainService.java file:

 

package com.example.myservice;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;

public class MainService extends Service {

    private static final String TAG = "My_Service";
    private boolean isRunning  = false;

    public MainService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        Log.i(TAG, "Service onBind");
        return null;
    }
    @Override
    public void onCreate() {
        Log.i(TAG, "Service onCreate");

        isRunning = true;
    }

    public native String  getString();

    static {
        System.loadLibrary("native-lib");
    }


    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        Log.i(TAG, "Service onStartCommand");

        //Creating new thread for my service
        //Always write your long running tasks in a separate thread, to avoid ANR
        new Thread(new Runnable() {
            @Override
            public void run() {

                for (int i = 0; i < 5; i++) {
                    try {
                        Thread.sleep(1000);
                    } catch (Exception e) {
                    }

                    if(isRunning){
                        Log.i(TAG, "Service running");
                        Log.i(TAG, getString());
                    }
                }

                //Stop service once it finishes its task
                stopSelf();
            }
        }).start();

        return Service.START_STICKY;
    }

    @Override
    public void onDestroy() {

        isRunning = false;

        Log.i(TAG, "Service onDestroy");
    }

}

 

Highlighted parts are JNI related.

 

MainActivity.java file:

package com.example.myservice;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.content.Context;
import android.util.Log;

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "My_Service";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Intent startServiceIntent = new Intent(this, MainService.class);
        Log.i(TAG, "Starting service from activity");

        startService(startServiceIntent);
        finish();
    }
}

 

MyBroadcastReceiver.java:

package com.example.myservice;


import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

public class MyBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Intent startServiceIntent = new Intent(context, MainService.class);
        context.startService(startServiceIntent);
    }
}

 

AndroidManifest.xml:

 

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myservice">

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <service
            android:name=".MainService"
            android:enabled="true"
            android:exported="true" />

        <receiver android:name=".MyBroadcastReceiver">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>

        <activity
            android:name=".MainActivity"
            android:theme="@android:style/Theme.Translucent.NoTitleBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

    </application>

</manifest>

 

My problem statement was to make a service which should be started at bootup and I also didn’t want any UI.

For first timer it is not suggested to use underscore (_) anywhere in package name or class name of java. You need to use _1 in cpp file for naming the function but if it doesn’t work out you will be confused. So keep it simple for the first time.

My experience was I already had underscore(_) in Java class name and also in package name. I did name the cpp function name correctly but forgot to use extern “C” banged my head for almost an hour and then created a separate project without underscore(_) only to find out the problem was extern “C” 

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s