Starting a Native Android Project
Native Android Project 建立顺序很重要,否则会出现意想不到的麻烦。
[Eclipse]
1、Launch Eclipse. In the main menu, go to File | New | Project....
2、Then, in the opened New project wizard, go to Android | Android Application Project and click on Next.
3、In the next screen, enter project properties as follows and click on Next again:
Click on Next twice, leaving default options, to go to the Create activity wizard screen. Select Blank activity with Fragment and click on Next.
5、Finally, in the Blank Activity screen, enter activity properties as follows:
6、Click on Finish to validate. After a few seconds, the wizard disappears and the project Store is displayed in Eclipse.
7、Add native C/C++ support to the project. Select the project Store in the Package Explorer view and from its right-click context menu, go to Android Tools | Add Native Support....
8、In the opened Add Android Native Support popup, set the library name to com_packtpub_store_Store and click on Finish.
9、The jni and obj directories are created in the project directory. The firrst directory contains one makefile Android.mk and one C++ source file com_packtpub_ store_Store.cpp.
10、Create a new Java class Store in src/com/packtpub/store/Store.java. From within a static block, load the com_packtpub_store_Store native library:
package com.packtpub.store;
public class Store {
static {
System.loadLibrary("com_packtpub_store_Store");
}
}
11、Edit src/com/packtpub/store/StoreActivity.java. Declare and initialize a new instance of Store in activity's onCreate(). Since we do not need them, remove the onCreateOptionsMenu() and onOptionsItemSelected() methods that may have been created by the Eclipse project creation wizard:
1 package com.packtpub.store; 2 ... 3 public class StoreActivity extends Activity { 4 private Store mStore = new Store(); 5 @Override 6 protected void onCreate(Bundle savedInstanceState) { 7 super.onCreate(savedInstanceState); 8 setContentView(R.layout.activity_store); 9 if (savedInstanceState == null) { 10 getFragmentManager().beginTransaction() 11 .add(R.id.container, new PlaceholderFragment()) 12 .commit(); 13 } 14 } 15 public static class PlaceholderFragment extends Fragment { 16 public PlaceholderFragment() { 17 } 18 @Override 19 public View onCreateView(LayoutInflater inflater, 20 ViewGroup container, 21 Bundle savedInstanceState) 22 { 23 View rootView = inflater.inflate(R.layout.fragment_store,container, false); 24 return rootView; 25 } 26 } }
12、Connect your device or emulator and launch the application. Select Store in the Package Explorer view and then navigate to Run | Run As | Android Application from the Eclipse main menu. Alternatively, click on the Run button in the Eclipse toolbar.
13、Select the application type Android Application and click on OK to get the following screen:
Let's create our first native method and call it from the Java side:
1、Open src/com/packtpub/store/Store.java and declare one native method to query the Store. This method returns int with the number of entries in it. There is no need to define a method body:
package com.packtpub.store; public class Store { static { System.loadLibrary("com_packtpub_store_Store"); } public native int getCount(); }
2、Open src/com/packtpub/store/StoreActivity.java and initialize the store. Use its getCount() method value to initialize the application title:
3、Generate a JNI header file from the Store class. Go to the Eclipse main menu and go to Run | External Tools | External Tools Configurations.... Create a new Program configuration with the following parameters described in the following screenshot:
Location refers to the javah absolute path, which is OS specific. On Windows, you can enter ${env_var:JAVA_HOME}\bin\javah.exe. On Mac OS X and Linux, it is usually /usr/bin/javah.
4、In the Refresh tab, check Refresh resources upon completion and select Specific resources. Using the Specify Resources... button, select the jni folder. Finally, click on Run to execute javah. A new file jni/com_packtpub_store_Store.h will then be generated. This contains a prototype for the native method getCount() expected on the Java side:
5、We can now implement jni/com_packtpub_store_Store.cpp so that it returns 0 when invoked. The method signature originates from the generated header file (you can replace any previous code) except that the parameter names have been explicitly specified:
6、Compile and run the application.
Debugging native Android applications
1、Create le jni/Application.mk with the following content:
APP_PLATFORM := android-14
APP_ABI := armeabi armeabi-v7a x86
2、Open Project Properties, go to C/C++ Build, uncheck Use default build command and enter ndk-build NDK_DEBUG=1:
3、In jni/com_packtpub_store_Store.cpp, place a breakpoint inside the Java_com_packtpub_store_Store_getCount() method by double-clicking on the Eclipse editor gutter.
4、Select the Store project in the Package Explorer or Project Explorer view and go to Debug As | Android Native Application. The application starts, but you will probably nd that nothing happens. Indeed, the breakpoint is likely to be reached before the GDB Debugger could attach to the application process.
5、Leave the application and reopen it from your device application menu. This time, Eclipse stops at the native breakpoint. Look at your device screen. The UI should be frozen because the main application thread is paused in native code.
6、Inspect variables in the Variables view and check the call stack in the Debug view. In the Expressions view, enter *pEnv.functions and open result expression to see the various functions provided by the JNIEnv object.
7、Step Over current instruction from the Eclipse toolbar or with the shortcut, F6 (you can also use Step Into with the shortcut, F7). The following instruc ons will be highlighted:
Resume the execution from the Eclipse toolbar or with the shortcut, F8. The application screen is displayed on your device again.
Terminate the application from the Eclipse toolbar or with the shortcut, Ctrl+F2. The application is killed and the Debug view is emptied.
NDK Debugger can also be tricky to use, such as when debugging native startup code. Indeed, GDB does not start fast enough to activate breakpoints. A simple way to overcome this problem is to make native code sleep for a few seconds when an application starts. To leave GDB enough time to attach an application process, we can do, for example, the following:
#include <unistd.h>
...
sleep(3); // in seconds.
Another solution is to launch a Debug session and then simply leave and re-launch the application from your device, as we have seen in the previous tutorial. This is possible because the Android application life cycle is such that an application survives when it is in the background, until the memory is needed. This trick only works if your application does not crash during startup though.
[Andrid Studio]
1、Launch Android Studio. On the welcome screen, select New Project... (or go to File | New Project... if a project is already opened).
2、From the New Project wizard, enter the following configuration and click on Next:
3、Then, select the minimum SDK (for example, API 14: Ice Scream Sandwich) and click on Next.
4、Select Blank Activity with Fragment and click on Next.
5、Finally, enter Activity Name and Layout Name names as follows and click on Finish:
6、Android Studio should then open the project:
7、Modify StoreActivity.java and create Store.java in the same way as we did in the Interfacing Java with C/C++ sec on in this chapter (Step 1 and 2).
8、Create the app/src/main/jni directory. Copy the C and Header files we created in the Interfacing Java with C/C++ sec on in this chapter (Step 4 and 5).
9、Edit app/build.gradle that has been generated by Android Studio. In defaultConfig, insert a ndk section to configure the module (that is, a library) name:
1 apply plugin: 'com.android.application' 2 android { 3 compileSdkVersion 21 4 buildToolsVersion "21.1.2" 5 defaultConfig { 6 applicationId "com.packtpub.store" minSdkVersion 14 7 targetSdkVersion 21 8 versionCode 1 9 versionName "1.0" 10 ndk { 11 moduleName "com_packtpub_store_Store" 12 } } 13 buildTypes { 14 release { 15 minifyEnabled false 16 proguardFiles getDefaultProguardFile('proguard-android. 17 txt'), 'proguard-rules.pro' 18 } } 19 } 20 dependencies { 21 compile fileTree(dir: 'libs', include: ['*.jar']) 22 compile 'com.android.support:appcompat-v7:21.0.3' 23 }
10、Compile and install the project on your device by clicking on installDebug in the Gradle tasks view of Android Studio.
Using your own handmade make files with Gradle is a bit tricky but not too complicated:
1、Copy the Android.mk and Application.mk files we created in the Interfacing Java with C/C++ section in this chapter into the app/src/main/jni directory.
2、Edit app/build.gradle.
3、Add an import for the OS "Class" and remove the first ndk section we created in the previous section:
1 import org.apache.tools.ant.taskdefs.condition.Os 2 apply plugin: 'com.android.application' 3 android { 4 compileSdkVersion 21 5 buildToolsVersion "21.1.2" 6 defaultConfig { 7 applicationId "com.packtpub.store" 8 minSdkVersion 14 9 targetSdkVersion 21 10 versionCode 1 11 versionName "1.0" 12 } 13 buildTypes { 14 release { 15 minifyEnabled false 16 proguardFiles getDefaultProguardFile('proguard-android. 17 txt'), 'proguard-rules.pro' 18 } 19 }
4、Still in the android section of app/build.gradle., insert a sourceSets.main section with the following:
jniLibs.srcDir, which defines where Gradle will find the generated libraries.
jni.srcDirs, which is set to an empty array to disable native code compilation through Gradle.
sourceSets.main { jniLibs.srcDir 'src/main/libs' jni.srcDirs = [] }
5、Finally, create a new Gradle task ndkBuild that will manually trigger the ndk-build command, specifying the custom directory src/main as the compilation directory.
Declare a dependency between the ndkBuild task and the Java compila on task to automatically trigger na ve code compilation:
1 task ndkBuild(type: Exec) { 2 if (Os.isFamily(Os.FAMILY_WINDOWS)) { 3 commandLine 'ndk-build.cmd', '-C', file('src/main').absolutePath } else { 4 commandLine 'ndk-build', '-C', file('src/main').absolutePath 5 } 6 } 7 tasks.withType(JavaCompile) { 8 compileTask -> compileTask.dependsOn ndkBuild 9 } 10 } 11 dependencies { 12 compile fileTree(dir: 'libs', include: ['*.jar']) 13 compile 'com.android.support:appcompat-v7:21.0.3' 14 }
6、Compile and install the project on your device by clicking on installDebug in the Gradle tasks view of Android Studio.

浙公网安备 33010602011771号