Mobile C++ Tutorials

Hello World App

Hello World App Part 1, C++

Updated: September 15, 2017
Photo Credit: Toni Rodrigo

In Part 1 of this tutorial, we will install 3rd party dependencies, render the Objective-C++ and JNI language bridge code with Djinni, write the C++ portion of our app, and finally run and test our app’s C++ code in Xcode.

Djinni is a tool developed by Dropbox to assist with utilizing code built in C++ to publish to both iOS and Android platforms. There are a lot of moving parts involved with this process, so this tutorial aims to get you a bare-bones project that implements some functionality built with C++.

Be sure you have completed the Cross-Platform C++ Dev Setup on OS X Yosemite tutorial before beginning this one.

Add Djinni to the project

We will utilize git submodules to add Djinni as a dependency to our project.

Create your project directory, ‘cd’ into it and enter the following commands into Terminal to add Djinni as a submodule:

git init
git submodule add https://github.com/dropbox/djinni.git deps/djinni

Set up the Djinni File

Djinni files are IDL (Interface Description Language) files that lay out the plan for our app’s cross-platform C++ functionality. Djinni generates much of the code needed for us, including all JNI and Objective-C++ bridge code, interfaces for C++ and Java, and an Objective-C delegate for iOS.

For this tutorial, our functionality will remain extremely simple. Copy/paste this code into a new file, helloworld.djinni:

hello_world = interface +c {
  static create(): hello_world;
  get_hello_world(): string;
}

The create() method will return an instance of our C++ object with the methods we outline in this IDL file, and the get_hello_world() function will return a string with “Hello World!” and the time of day.

Create the Djinni Shell Script

This is the script that will run the djinni command, customized with the options that we require for our app. We’ll name this file run_djinni.sh and place it in the root directory of our project so it is easy to find:

run_djinni.sh

#! /usr/bin/env bash

### Configuration

# Djinni IDL file location
djinni_file="helloworld.djinni"

# C++ namespace for generated src
namespace="helloworld"

# Objective-C class name prefix for generated src
objc_prefix="HW"

# Java package name for generated src
java_package="com.mycompany.helloworld"


### Script

# get base directory
base_dir=$(cd "`dirname "0"`" && pwd)

# get java directory from package name
java_dir=$(echo $java_package | tr . /)

# output directories for generated src
cpp_out="$base_dir/generated-src/cpp"
objc_out="$base_dir/generated-src/objc"
jni_out="$base_dir/generated-src/jni"
java_out="$base_dir/generated-src/java/$java_dir"

# clean generated src dirs
rm -rf $cpp_out
rm -rf $jni_out
rm -rf $objc_out
rm -rf $java_out 

# execute the djinni command
deps/djinni/src/run \
   --java-out $java_out \
   --java-package $java_package \
   --ident-java-field mFooBar \
   --cpp-out $cpp_out \
   --cpp-namespace $namespace \
   --jni-out $jni_out \
   --ident-jni-class NativeFooBar \
   --ident-jni-file NativeFooBar \
   --objc-out $objc_out \
   --objc-type-prefix $objc_prefix \
   --objcpp-out $objc_out \
   --idl $djinni_file

At this point, you should be able to run the Djinni script and generate all of the files needed for the JNI and Objective-C++ language bridges, the C++ and Java interfaces, and the Objective-C delegate:

$ sh ./run_djinni.sh

The first time you run the script it may take a few minutes for Djinni to download dependencies and run it’s Scala build.

Now you should be able to peek in the new ‘generated-src’ folder and see all of the files generated by Djinni. You can see what a major pain it would be to write all of the bridge code by hand!

Write Our Cross-Platform C++ Code

One analogy for developing cross-platform apps in C++ is to compare it to the front-end and back-end of server- and client-side application development. Much like a back-end server exposes a limited set of functionality to websites and apps through an API, our C++ code acts as a ‘back-end’ that exposes functionality to our native UI code. The native Java and Objective-C code then act as the ‘front-end’, calling the exposed functionality when needed as the user interacts with the native UI.

In this part of the tutorial, we are writing what equates to the back end code in the above analogy, and in parts 2 and 3 we will write the front end code.

First, let’s create a new ‘src’ folder in our project folder structure, with a subfolder of ‘cpp’. This will house all of our C++ code outside of any project files, so that all of the projects can access the same C++ source code. In this new folder, create two new files ‘hello_world_impl.hpp’ and ‘hello_world_impl.cpp’:

src/cpp/hello_world_impl.hpp:

#pragma once
 
#include "hello_world.hpp"
 
namespace helloworld {
    
    class HelloWorldImpl : public helloworld::HelloWorld {
        
    public:
        
        // Constructor
        HelloWorldImpl();
        
        // Our method that returns a string
        std::string get_hello_world();
        
    };
    
}

src/cpp/hello_world_impl.cpp:

#include "hello_world_impl.hpp"
#include <string>
 
namespace helloworld {
    
    std::shared_ptr<HelloWorld> HelloWorld::create() {
        return std::make_shared<HelloWorldImpl>();
    }
    
    HelloWorldImpl::HelloWorldImpl() {
 
    }
    
    std::string HelloWorldImpl::get_hello_world() {
        
        std::string myString = "Hello World! ";
        
        time_t t = time(0);
        tm now=*localtime(&t);
        char tmdescr[200]={0};
        const char fmt[]="%r";
        if (strftime(tmdescr, sizeof(tmdescr)-1, fmt, &now)>0) {
            myString += tmdescr;
        }
        
        return myString;
        
    }
    
}

Now we’ve built out our shared, cross-platform functionality in C++ so it can be called later by both Java and Objective-C. In a more complex app, this would include our cross-platform business logic such as SQLite database interactions and web API calls.

Create a new Xcode Project

Both Xcode and Android Studio can be used to build and run C++ projects. Android Studio has a few extra steps to see C++ output in the console, though, so we will just use Xcode for now.

Open Xcode, and either select ‘Create a new Xcode project’ from the splash screen or go to File > New > Project from the top nav.

In the dialog that appears, select ‘macOS‘ from the menu at the top, then select ‘Command Line Tool’ and then click the Next button:

Xcode C++ Choose Template

In the next dialog, fill out your app name and organization name, and be sure to select ‘C++’ for the language:

Xcode C++ Choose Options

Finally, save the project in a new directory called ‘xcode_project’:

Xcode Project Directory

Now the new XCode project should open up, and if you run the project (Product > Run), you should see “Hello, World!” output to the console. This is coming from the default main.cpp file in the project, and not our custom C++ code yet, though!

Add Our C++ Source

Now we need to add our C++ source files to the project, including the hello_world.hpp interface generated by Djinni, and both of our hand-coded implementation files. At this point, our project’s folder structure should look like this:

Xcode C++ Folders

Drag the following files into Xcode’s folder structure, inside the HelloWorld project folder with the main.cpp file:

generated-src/cpp/hello_world.hpp
src/cpp/hello_world_impl.cpp
src/cpp/hello_world_impl.hpp

If the resulting dialog, be sure to select ‘Create folder references’ and not ‘Copy items if needed’, otherwise Xcode will create duplicates of the files inside of the project folder. This would result in them being out of sync with the C++ code in our src folder. Also, be sure you check the box next to your deployment target so the files will be included when you publish:

Xcode Create Folder References

Now your Xcode project should look like the following:

C++ Project

Our last step is to modify the main.cpp file to call our custom “Hello World” function. Replace the contents of the file with the following:

xcode_project/HelloWorld/HelloWorld/main.cpp:

#include <iostream>
#include "hello_world_impl.hpp"

using namespace std;
using namespace helloworld;
 
int main(int argc, const char * argv[]) {
    HelloWorldImpl hw = HelloWorldImpl();
    string myString = hw.get_hello_world();
    cout << myString << "\n";
    return 0;
}

Now if you run the project (press the ‘play’ button, or select Product > Run) you should see ‘Hello World!’ in the console at the bottom right, only now including the time of day from our C++ code!

Hello World C++ Result

In the next tutorial, we’ll tackle implementing our working C++ code in Objective-C, and publishing to an iOS device or simulator.

Cross-Platform C++ Dev Setup on macOS Sierra
Hello World App Part 2, iOS