SWIG is a tool for generating cross-language interfaces - it provides interoperability of C++ and other languages (C++ and Java in our case). SWIG just simplifies and automizes cross-language interaction; otherwise, you may end up with thousands of lines of handwritten JNI code - but SWIG covers this for you. This guide is for newbies (Part 1) and for those who experienced in SWIG (part 2). I'm starting from basic setup and usage and ending with complex & weird cases encountered in development. The latter cases are not so complex, rather usual for modern languages, which SWIG doesn't support yet (as lambdas). This guide is practical. In opposition to overcomplicated huge-volume SWIG documentation, this guide is showing the cases practically. The bits developed by myself while working on the different projects or taken from StackOverflow. This guide allows you to quick-start an Android Studio project and giving practical examples of using SWIG. The link to the Android Studio project is here. This guide is Android-first. The goal was to make it simple to onboard for Android developers. There are many articles about SWIG, but they are mainly for desktop Java applications, and it is quite an overhead to just try them on Android to check if the solution for the particular problem is working. While this guide includes an Android Studio project, with which you can play around instantly. Of course, all the information given here applies to any Java application. Warning! I should warn you, that nowadays cross-platform development offers powerful tools. If you are developing a new application it is much more cost-efficient in practice to use ReactNative, Flutter of Kotlin-Native than the SWIG. While SWIG is more suitable to connect the C++ library or existing C++ application core. Enjoy :) Installation and Starting Simple cases Calling C++ from Java. Writing the SWIG script. Calling Java from C++ (Directors) Shared pointer to an object C++ std:: containers Type downcast Resources  Install the latest Android Studio (3.5.3), then the latest NDK (using Android Studio SDK manager), and the latest SWIG tool (4.0.1). Add SWIG to your PATH environment variable. The versions are given at the moment of writing this article. Create new Android Studio project: File -> New -> New Project -> Select "Native C++" -> Chose project parameters and location, use Java* language -> Press "Finish". *You can use Kotlin, no difference using SWIG. This guide is just written in Java. Now you've got a simple project template, which includes C++ code. Run it on your device. In short, except for the standard project structure for Java, your new project includes the: file with C++ code (app/src/main/cpp/native-lib.cpp) Rules to build your C++ code into a library which will be packaged into your APK (app/src/main/cpp/CMakeLists.txt) * All paths here and later are relative to the Android Studio project root. Then you load your library dynamically in Java code: And now you can use the C++ code through JNI. You can read more about the basic C++ usage in Android here. And about JNI specifically here. In any case, just check the article and note how many JNI code is required to use Java array or to call a simple method. JNI is a low-level tool and most of the JNI code is not checkable by the compiler - we will know about the error only in the runtime. That's why we are using SWIG, which automizes the process to generate JNI boilerplate code. If you are known with SWIG, you can jump to the next section. SWIG is a tool for generating a JNI layer between Java and C++ automatically, based on the set of rules. On the input, it takes a public section of C++ header files, and on the output generates C++/JNI and Java files which can be included into the project and interlanguage interaction becomes seamless. Not as seamless, as Obj-C/C++ boundary, and has some caveats, but much simpler than pure JNI. For simple situations and basic types, the rules are already existing in SWIG. For custom cases, you have to write your own rules. This is hard to understand at first, but once the rules are written, generating new interfaces become seamless - just run a script once more, when your header files have changed. However, SWIG has downsides - it is overcomplicated, bloated, and has very-very large documentation. Best to learn SWIG on practice. We are using the SWIG tool of the latest version 4.0.1. It should be installed on your PC. It doesn't interact with IDE. It is called from the external script. The SWIG tool should be added to your PATH environment variable. To call C++ from Java. Imagine we have Example C++ class in 'ActivityModel.h'. And implementation in 'ActivityModel.cpp'. Now create the swig directory inside your project. We need to include the header into a special SWIG file which will be handled by our SWIG script. Add into the swig directory file SwigAndroidGuide.i with content: and add the script to run SWIG (swig/run_shig.sh). This is done for bash and will run on Linux/Mac. For Windows, you have to re-write the script for Windows terminal or try to using Cygwin. Run this script.  If using git, you can see the new files (git diff): Java files are going to app/src/main/java/com/goldberg/swigandroidguide/swiggenerated directory. There are two helper Java files SwigAndroidGuide.java and SwigAndroidGuideJNI.java; and one Java file per processed C++ class, currently only the ActivityModel.java. Generated C++ helper code is going to app/src/main/cpp/swig-generated directory. Currently only one file generated - SwigAndroidGuide_wrap.cpp. In the next chapter you will get one more file there - SwigAndroidGuide_wrap.h. So usually there are two files. After running the SWIG script, we got the following Java code in ActivityModel.java. Note the generated Java class has SWIG internal helper code, but you can find our functions inside the class. You can call this from Java as: If you run your project now, it will crash with an error: That's because your C++ files were not added to the project. Go to CMakeLists.txt and add your ActivityModel.cpp file into the existing shared library: After sync (run Gradle Sync) you will be able to run your project. Log output is now correct: Hooray! The C++ code invocation is working. Now we've done basic SWIG integration. After this is done, no need to add SWIG-generated files into the project manually. They are already added to the project - the single C++ file SwigAndroidGuide_wrap.cpp, which only modified by re-generation; and Java as a directory, so all newly generated Java files are included automatically. If error is issued by SWIG, you will find SwigAndroidGuide_wrap.cpp file deleted and app/src/main/java/com/goldberg/swigandroidguide/swiggenerated/ directory empty. This is because our script run_swig.sh deletes all the generated files, and then SWIG generated them again. You have to fix the error and run SWIG again. To call Java from C++ we have to use SWIG directors. SWIG director is a feature allowing cross-language polymorphism. In simpler language, with directors, Java classes can be 'inherited' from the C++ classes. Under the hood, SWIG creates a Java class, that has the same methods as a C++ class, and generates code to bind them; then you inherit your Java implementation class from the SWIG-generated Java class. Let's create IAndroidActivity class in app/src/main/cpp/IAndroidActivity.h to allow C++ to control Android Activity. To call this from C++, let's add a new function into ActivityModel class in app/src/main/cpp/ActivityModel.h (the same way as in previous chapter): And then call this function in app/src/main/cpp/ActivityModel.cpp: In the SWIG interface file we should enable directors to allow Java inheritance of C++ classes. SwigAndroidGuide.i:  Re-run SWIG script now (swig/run_swig.sh). If you run git diff after this, you will notice the new file with the strange name: app/src/main/java/com/goldberg/swigandroidguide/swiggenerated/SWIGTYPE_p_std__string.java Prefix SWIGTYPE_p_ means SWIG has not enough information to process a particular type. _std__string.java means std::string was not processed properly. SWIG can process only types integral to C++ by default, like int, char*, etc. But SWIG instructions for most of the std types and containers SWIG are already written. They reside in the SWIG include directory (where the SWIG program is installed). To properly process std::string include std_string.i for processing. Modify your SWIG file SwigAndroidGuide.i: Re-run SWIG script swig/run_swig.sh. Notice IAndroidActivity class is added in your Java folder. Let's create a Java implementation for our C++ interface. We can't extend our MainActivity from IAndroidActivity, as it already extends an AppCompatActivity. Unfortunately, it's impossible to create a pure Java interface with SWIG. Let's create an inner class, and implement the showToast(String text) method in it. Now we can call C++ code that will callback to showToast(String text). Voilà! Now, when you run the application, you will see the toast with text sent from C++. And log: D/MainActivity: showToast() Will show toast with text: Toast from C++  In many cases, you may want to use std::shared_ptr while developing in C++. With SWIG it is possible and very simple to work with. Let's create C++ class Message in app/src/main/cpp/Message.h. And use shared_ptr<message> inIAndroidActivity.h`: And call it from C++, in ActivityModel.cpp: Then, in SWIG file SwigAndroidGuide.i: Now, when you re-run SWIG, it will generate proper interfaces for the shared_ptr argument - shared_ptr<Message>. Let's implement it in Java, in MainActivity.java: Run the application, and you'll get proper log output: D/MainActivity: Message sent: '22 Greetings!'  As we were done wrapping of std::string in the previous section, we can do with most (if not any) of C++ standard library containers. Let's try on an example of std::vector. This applies to all other containers. Create new file app/src/main/cpp/Types.h: Create new file app/src/main/cpp/PhotoMessage.h: Create a function in IAndroidActivity.h to use our new class: And use it from C++, in ActivityModel.cpp. For std::vector we must specify the template we want SWIG to generate wrapper to. In our case %template(VectorByte) std::vector<byte>. The unique template name should be passed in a %template(NAME) argument. Modify SWIG file SwigAndroidGuide.i: Now run SWIG script swig/run_swig.sh, note it will generate Java class VectorByte (as we specified in %template(NAME)). See, it mirrors the std::vector functions. They now can be called from Java. Also note, the generated Java class is templated for type short. This is just because our C++ byte equals unsigned char, and the latter maps to Java type short. For other types, you will not get such a problem. The problem with this 'default' implementation of containers with SWIG - it allows only per-element access. While this is ok when you having vector<Message>; but this is a bottleneck, if you have to pass big amounts of data through vector<byte>, as accessing each byte will be a dedicated JNI call. We will address both problems in later chapter (Part 2 : byte[][]). Generated VectorByte.java: Now let's make Java implementation in MainActivity.java: Run an application, and you will see the proper log output: D/MainActivity: Photo message sent: '27 PhotoMessage!' with bytes: '78 64 35 '  In the previous document section, we have created a class PhotoMessage inherited from Message And we created a separate function for PhotoMessage to be passed to Java: We did this because downcasting by the inheritance tree of C++ doesn't work in Java. See example. Let's pass child object PhotoMessage to a function expecting base type Message: In Java, you will get the object of type Message, which is legit, but you cannot downcast it, even if the underlying C++ object is of child type PhotoMessage. So, how to we can enable downcasts in Java? SWIG documentation tells us how to support type downcasts - by extending our classes with function, that we can call from Java, and which will implement C++ dynamic_cast functionality. In SWIG code this looks very simple: %extend means your class will get an extra function. %extend unfolds to a member function in Java, which internally calls static C++ function (non-member of your C++ class) with code we put there in %extend definition. Add the code from the above snippet to the bottom of your SWIG file swig/SwigAndroidGuide.i. Then run SWIG generation swig/run_swig.sh. See that PhotoMessage got and extra function in PhotoMessage.java: And we are looking the first time into app/src/main/cpp/swig-generated/SwigAndroidGuide_wrap.cpp. Just to get an idea of how the SWIG extension %extend interacts with our code. Now, remove the specific function IAndroidActivity::sendPhotoMessage(shared_ptr<photomessage>) from C++ and its implementation in Java and re-run SWIG script swig/run_swig.sh again. Alter implementation of IAndroidActivity.sendMessage in Java, as now it supports polymorphic arguments. But the typecasting logic works as in C++ (not like 'standard' Java) - you doing dynamic_cast, and then checking the argument for null, as in the following code from MainActivity.java. And in ActivityModel.cpp: Run the application and check that log is valid: The problem with this chunk of SWIG code - we must copy it for all types we want to support downcast. The solution to the problem is SWIG macro %define. It unfolds just like C++ macro. Put this into the new file swig/dynamic_cast_extension.i. We still need to unfold this macro for each type, but now it is a one-liner. Do changes in your SwigAndroidGuide.i: Now much better. Just re-run SWIG run_swig.sh and verify the application is working properly. Now we dismantled the SWIG basics in Android and simple cases. It looks very tangled and confusing at the beginning, but after small practice, everything falls into place. I invite you to Part 2 of the guide, where we talk about peculiar/weird cases, typemaps, and debugging. Android Studio project Android JNI Application With NDK Java Native Interface (JNI)