SlideShare a Scribd company logo
Mobile Application Development with
JUCE and Native API’s
Adam Wilson
JUCE Summit 2015
Creating mobile apps that mix JUCE components
with native iOS or Android UI elements.
Why?
• JUCE is a cross-platform framework
• Write once, run anywhere
JUCE Components were designed for
desktop apps, not for touch screen devices.
Limited support for gestures
Hard to get the feel right for common UI interactions
E.g. ListBox component
E.g. ListBox component
Needs adapting to respond to finger gestures
E.g. ListBox component
Needs adapting to respond to finger gestures
Hard to get it to scroll smoothly when there is e.g. audio processing
happening in the background
Navigation
Navigation
E.g. swipe to move between pages
Navigation
E.g. swipe to move between pages
Problem: Components grab mouse events
Solution: Utilise native API’s
Platform Language API
Android Java
Android API’s and Android
Support Libraries
iOS Objective-C / Swift Cocoa Touch
Use Native API’s for:
Scrollable Lists
Navigation
User input
Database access
Use JUCE for:
Audio and data processing
Custom graphics and animation (OpenGL)
Custom or specialised GUI elements 

e.g. MidiKeyboardComponent
Advantages of this approach
Advantages of this approach
Familiar UI elements using each platform’s native idioms

Advantages of this approach
Familiar UI elements using each platform’s native idioms
Smooth scrolling, gesture support 

Advantages of this approach
Familiar UI elements using each platform’s native idioms
Smooth scrolling, gesture support
Comprehensive toolkits for creating GUI’s: Xcode and Android Studio

Advantages of this approach
Familiar UI elements using each platform’s native idioms
Smooth scrolling, gesture support
Comprehensive toolkits for creating GUI’s: Xcode and Android Studio
No need to code transitions and other animations - these are provided by the native
API’s
Advantages of this approach
Familiar UI elements using each platform’s native idioms
Smooth scrolling, gesture support
Comprehensive toolkits for creating GUI’s: Xcode and Android Studio
No need to code transitions and other animations - these are provided by the native
API’s
Use a local database e.g. SQLite, Couchbase Mobile, Firebase and connect directly to
your UI

Disadvantages of this approach
Disadvantages of this approach
Designing and coding part of your UI for each platform



Disadvantages of this approach
Designing and coding part of your UI for each platform
Potentially complicated communication between languages:



Java C++
Objective-C C++
Objective-C C++Swift
How?
There are two things to consider:
How?
There are two things to consider:
1. Mixing JUCE components with native UI
How?
There are two things to consider:
1. Mixing JUCE components with native UI
2. Passing data between C++ and Java, or C++ and Objective-C
Disclaimer:
Assume that most of the time we will only want to call C++
from the native UI code, not the other way round.
Android + JUCE: UI
We can now use Android Studio!

(This turns out to be a nice IDE also for C++ development)
Android + JUCE: UI
Introjucer’s Android exporter generates a Java Activity class
Android + JUCE: UI
Introjucer’s Android exporter generates a Java Activity class
The default activity is full screen
Android + JUCE: UI
Introjucer’s Android exporter generates a Java Activity class
The default activity is full screen
We want our JUCE component as part of a layout
Android + JUCE: UI
Introjucer’s Android exporter generates a Java Activity class
The default activity is full screen
We want our JUCE component as part of a layout
So we need to do some modifications
Android + JUCE: UI
viewHolder = new ViewHolder (this);

setContentView (viewHolder);
In your default generated Activity class onCreate:
Android + JUCE: UI
viewHolder = new ViewHolder (this);

setContentView (viewHolder);
In your default generated Activity class onCreate:
Would become something like:
viewHolder = new ViewHolder (this);

setContentView(R.layout.main_activity);
LinearLayout juceViewContainer = (LinearLayout) findViewById(R.id.juce_view_container);

juceViewContainer.addView(viewHolder);
Android + JUCE: UI
viewHolder = new ViewHolder (this);

setContentView (viewHolder);
In your default generated Activity class onCreate:
Would become something like:
viewHolder = new ViewHolder (this);

setContentView(R.layout.main_activity);
LinearLayout juceViewContainer = (LinearLayout) findViewById(R.id.juce_view_container);

juceViewContainer.addView(viewHolder);
main_activity.xml layout file
Android + JUCE: UI
viewHolder = new ViewHolder (this);

setContentView (viewHolder);
In your default generated Activity class onCreate:
Would become something like:
viewHolder = new ViewHolder (this);

setContentView(R.layout.main_activity);
LinearLayout juceViewContainer = (LinearLayout) findViewById(R.id.juce_view_container);

juceViewContainer.addView(viewHolder);
juce window within layout
main_activity.xml layout file
Android + JUCE: UI
If we want to use the recent Android Support Libraries, which are necessary
for Material Design style apps then we also need to change the base class
(superclass) from Activity to AppCompatActivity:



import android.support.v7.app.AppCompatActivity;
//…
public class JuceActivity extends AppCompatActivity
{
//…
}
Android + JUCE
Android + JUCE: Data
Declare our JNI functions in Java and implement them in C++
The C++ functions could be getters, setters, actions etc.
Android + JUCE: Data
Sending data to C++:
Android + JUCE: Data
#if JUCE_ANDROID



JUCE_JNI_CALLBACK (JUCE_ANDROID_ACTIVITY_CLASSNAME, setMessage, void, (JNIEnv* env,
jclass, jstring message))

{

SharedResourcePointer<MainContentComponent> mainComponent;



mainComponent->message = juceString (env, message);

mainComponent->repaint();

}



#endif
Sending data to C++:
Android + JUCE: Data
#if JUCE_ANDROID



JUCE_JNI_CALLBACK (JUCE_ANDROID_ACTIVITY_CLASSNAME, setMessage, void, (JNIEnv* env,
jclass, jstring message))

{

SharedResourcePointer<MainContentComponent> mainComponent;



mainComponent->message = juceString (env, message);

mainComponent->repaint();

}



#endif
Sending data to C++:
Android JNI Helper method
converts jstring to JUCE String
Android + JUCE: Data
#if JUCE_ANDROID



JUCE_JNI_CALLBACK (JUCE_ANDROID_ACTIVITY_CLASSNAME, setMessage, void, (JNIEnv* env,
jclass, jstring message))

{

SharedResourcePointer<MainContentComponent> mainComponent;



mainComponent->message = juceString (env, message);

mainComponent->repaint();

}



#endif
This is a global function
Sending data to C++:
Android + JUCE: Data
Declare it in your Activity class:
public static native void setMessage (String message);
Android + JUCE: Data
Declare it in your Activity class:
public static native void setMessage (String message);
JuceActivity.setMessage("My new message");
and then wherever you want to call that function, e.g.
Android + JUCE: Data
We might also want to pull data from our C++ code - e.g. a list of menu items
Android + JUCE: Data
Pulling data from C++ takes a little more work, e.g. in the case of a string:
JUCE_JNI_CALLBACK (JUCE_ANDROID_ACTIVITY_CLASSNAME, getJsonDataBytes, jbyteArray, (JNIEnv* env,
jclass))

{

SharedResourcePointer<MainContentComponent> mainComponent;

String jsonData = mainComponent->data.toJson();



int byteCount = jsonData.length();

const jbyte* nativeString = reinterpret_cast<const jbyte*> ((const char *) jsonData.toUTF8());

jbyteArray bytes = env->NewByteArray (byteCount);

env->SetByteArrayRegion (bytes, 0, byteCount, nativeString);



return bytes;

}
Android + JUCE: Data
In your Activity class:
public static String getJsonData()

{

return new String(getJsonDataBytes(), Charset.forName("UTF-8"));

}
private static native byte[] getJsonDataBytes();
Android + JUCE: Data
Thats it!
If you do need to call Java from C++, you need to add your function
definition to juce_android_JNIHelpers.h



(I’ve not had to do this yet)
iOS + JUCE: UI
JUCE Window is a UIView
Therefore we can add it as a subview to any other view in an iOS app

E.g. a UIViewController
iOS + JUCE: UI
We need to modify the MainWindow class and make it an Objective-C++ file (.mm)
iOS + JUCE: UI
We need to modify the MainWindow class and make it an Objective-C++ file (.mm)
Here we:
1. Create a UIWindow
iOS + JUCE: UI
MainWindow::MainWindow (String name) : DocumentWindow (name,
Colours::lightgrey,
DocumentWindow::allButtons)
{
UIWindow* window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
iOS + JUCE: UI
We need to modify the MainWindow class and make it an Objective-C++ file (.mm)
Here we:
1. Create a UIWindow
2. Create a UIView
iOS + JUCE: UI
MainWindow::MainWindow (String name) : DocumentWindow (name,
Colours::lightgrey,
DocumentWindow::allButtons)
{
UIWindow* window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
UIView* juceView = [[UIView alloc] initWithFrame: [[UIScreen mainScreen] bounds]];
iOS + JUCE: UI
We need to modify the MainWindow class and make it an Objective-C++ file (.mm)
Here we:
1. Create a UIWindow
2. Create a UIView
3. Add our Component to the UIView
iOS + JUCE: UI
MainWindow::MainWindow (String name) : DocumentWindow (name,
Colours::lightgrey,
DocumentWindow::allButtons)
{
UIWindow* window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
UIView* juceView = [[UIView alloc] initWithFrame: [[UIScreen mainScreen] bounds]];
MainWindow::addComponentToUIView (mainComponent.get(), juceView);
iOS + JUCE: UI
We need to modify the MainWindow class and make it an Objective-C++ file (.mm)
Here we:
1. Create a UIWindow
2. Create a UIView
3. Add our Component to the UIView
4. E.g. add our JUCE UIView as a subview of a UIViewController
iOS + JUCE: UI
MainWindow::MainWindow (String name) : DocumentWindow (name,
Colours::lightgrey,
DocumentWindow::allButtons)
{
UIWindow* window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
UIView* juceView = [[UIView alloc] initWithFrame: [[UIScreen mainScreen] bounds]];
MainWindow::addComponentToUIView (mainComponent.get(), juceView);
JuceViewController* juceViewController = // Subclass of UIViewController
[[JuceViewController alloc] initWithContentView: juceView];
juceViewController.contentView = juceView;
//…
iOS + JUCE: UI
void MainWindow::addComponentToUIView (Component& component, void* uiView)
{
component.addToDesktop (0, uiView);
UIView* view = (UIView*) uiView;
component.setVisible (true);
component.setBounds (view.bounds.origin.x, view.bounds.origin.y,
view.bounds.size.width, view.bounds.size.height);
}
Handy function:
iOS + JUCE
iOS + JUCE: Data
We need to two layers
One that is visible to C++, and the other that is visible to Objective-C.
Lets call these DataController and Wrapper
iOS + JUCE: Data
DataController.h Wrapper.h
DataController.cpp Wrapper.mm
C++ Objective-C++
iOS + JUCE: Data
DataController.h Wrapper.h
DataController.cpp Wrapper.mm
JuceHeader.h
iOS + JUCE: Data
DataController.h Wrapper.h
DataController.cpp Wrapper.mm
Only basic C types exposed
iOS + JUCE: Data
/**
* Methods to expose to Objective-C
* Note that only basic C types are exposed
*/
struct DataController
{
DataController();
/** Get JSON string of all message data */
const char* getJsonData();
/** Set message and repaint MainContentComponent */
void setMessage (const char *title, const char* message);
};
DataController.h
iOS + JUCE: Data
DataController.h Wrapper.h
DataController.cpp Wrapper.mm
C++ Objective-C++
iOS + JUCE: Data
#include "JuceHeader.h"
#include "DataController.h"
#include "MainComponent.h"
#include "Data.h"
void DataController::setMessage (const char *title, const char* message)
{
SharedResourcePointer<MainContentComponent> mainComponent;
mainComponent->title = (String) title;
mainComponent->message = (String) message;
mainComponent->repaint();
}
const char* DataController::getJsonData()
{
SharedResourcePointer<MainContentComponent> mainComponent;
return mainComponent->data.toJson().toRawUTF8();
}
DataController.cpp
iOS + JUCE: Data
DataController.h Wrapper.h
DataController.cpp Wrapper.mm
C++ Objective-C++
iOS + JUCE: Data
#import <Foundation/Foundation.h>
@interface Wrapper : NSObject
/** Set message and repaint JUCE MainContentComponent */
- (void)setMessage:(NSString*) message;
/** Get Data as JSON String */
- (NSString*)getJsonData;
@end
Wrapper.h
iOS + JUCE: Data
DataController.h Wrapper.h
DataController.cpp Wrapper.mm
C++ Objective-C++
iOS + JUCE: Data
#import <Foundation/Foundation.h>
#import "Wrapper.h"
#import "DataController.h"
@interface Wrapper ()
{
DataController* wrapped;
}
@end
@implementation Wrapper
- (id)init
{
self = [super init];
if (self)
{
wrapped = new DataController();
if (!wrapped) self = nil;
}
return self;
}
Wrapper.mm
http://philjordan.eu/article/mixing-objective-c-c++-and-objective-c++
iOS + JUCE: Data
#import <Foundation/Foundation.h>
#import "Wrapper.h"
#import "DataController.h"
@interface Wrapper ()
{
DataController* wrapped;
}
@end
@implementation Wrapper
- (id)init
{
self = [super init];
if (self)
{
wrapped = new DataController();
if (!wrapped) self = nil;
}
return self;
}
Wrapper.mm
- (void)setMessage: (NSString*) message
{
const char* messageChar = [message UTF8String];
wrapped->setMessage(messageChar);
}
- (NSString*)getJsonData
{
const char* jsonCharPointer = wrapped->getJsonData();
NSString* jsonDataString = [NSString stringWithFormat:@“%s”
jsonCharPointer];
return jsonDataString;
}
- (void)dealloc
{
delete wrapped;
[super dealloc];
}
@end
http://philjordan.eu/article/mixing-objective-c-c++-and-objective-c++
iOS + JUCE: Data
#import <Foundation/Foundation.h>
#import "Wrapper.h"
#import "DataController.h"
@interface Wrapper ()
{
DataController* wrapped;
}
@end
@implementation Wrapper
- (id)init
{
self = [super init];
if (self)
{
wrapped = new DataController();
if (!wrapped) self = nil;
}
return self;
}
Wrapper.mm
- (void)setMessage: (NSString*) message
{
const char* messageChar = [message UTF8String];
wrapped->setMessage(messageChar);
}
- (NSString*)getJsonData
{
const char* jsonCharPointer = wrapped->getJsonData();
NSString* jsonDataString = [NSString stringWithFormat:@“%s”
jsonCharPointer];
return jsonDataString;
}
- (void)dealloc
{
delete wrapped;
[super dealloc];
}
@end
http://philjordan.eu/article/mixing-objective-c-c++-and-objective-c++
iOS + JUCE: Data
Any Objective-C class can now call the exposed methods via

#import "DataControllerWrapper.h"
iOS + JUCE: Data
Any Objective-C class can now call the exposed methods via

This includes Swift - in that case it would be in e.g. MyJuceApp-Header.h

(This is a special header file that allows us to expose Objective-C methods
to Swift)
I would recommend using Swift if possible
#import "DataControllerWrapper.h"
iOS + JUCE: Data
If we want to call Objective-C (or Swift!) from C++ then we need to employ
the PIMPL idiom
This is the subject of another talk!

See http://philjordan.eu/article/mixing-objective-c-c++-and-objective-c++
Tying things together
Seperate MainWindow class from Main.cpp
Have an Objective-C++ version (e.g. iosWindow.h and iosWindow.mm)
Then in your Main.cpp:





#if JUCE_IOS
#include "iosMainWindow.h"
#else
#include "MainWindow.h"
#endif
Thanks for listening!
Example project source code available at:
github.com/adamski/juce-native-navigation
adam@codegarden.co.uk

More Related Content

PPTX
Geek squad (completed)
DOCX
Topics for final year project
PDF
Final Report for Summer internship at Software House
PDF
Paddington Heights
PPTX
Symbian OS
PDF
Financial Analysis on Maybank and CIMB (Bank Management)
PPT
Green Finance: Business Opportunities and Role of Financial Institutions
PPS
Java Presentation
Geek squad (completed)
Topics for final year project
Final Report for Summer internship at Software House
Paddington Heights
Symbian OS
Financial Analysis on Maybank and CIMB (Bank Management)
Green Finance: Business Opportunities and Role of Financial Institutions
Java Presentation

What's hot (13)

DOCX
An Internship report on Evaluation of Credit Risk management
PPTX
Introduction to Risk
PDF
InternshipReport_Sabiha_DIIT (1).pdf
PDF
General Banking Activities & Financial Performance of Agrani Bank Limited
PDF
MBA (IT) SIP Report on RIInfotech
PPTX
Janata Bank presentation
PPTX
ISLAMIC BANK & FINANCE Chapter 3
PPT
Eoif Mudarabah Musharakah
PPTX
HSBC Project or Presentation
PPTX
Private and public banks comparison
PDF
Synopsis on android application
PPTX
Internship Defense Presentation
An Internship report on Evaluation of Credit Risk management
Introduction to Risk
InternshipReport_Sabiha_DIIT (1).pdf
General Banking Activities & Financial Performance of Agrani Bank Limited
MBA (IT) SIP Report on RIInfotech
Janata Bank presentation
ISLAMIC BANK & FINANCE Chapter 3
Eoif Mudarabah Musharakah
HSBC Project or Presentation
Private and public banks comparison
Synopsis on android application
Internship Defense Presentation
Ad

Similar to Mobile Application Development with JUCE and Native API’s (20)

PPTX
Independent Development and Writing Your Own Engine
PDF
Android Bootcamp
PDF
Introduction to the Android NDK
PDF
Android Development
PPTX
Using the android ndk - DroidCon Paris 2014
PDF
Using the Android Native Development Kit (NDK)
PPT
Cross-Platform Mobile Development in Visual Studio
PPT
Synapse india mobile apps update
PDF
Programming Android
PPT
Synapse india reviews on i phone and android os
KEY
Kirin - Making Single Page Web Apps with a Native UI
PPT
Industrial Training in Android Application
PPTX
PDF
Android Internals
PDF
"JavaME + Android in action" CCT-CEJUG Dezembro 2008
PDF
Android Internals (This is not the droid you’re loking for...)
PDF
Android++ A Cross Platform Framework
PPTX
PPTX
Developing a mobile cross-platform library
PPT
Alternatives to Java for Android development
Independent Development and Writing Your Own Engine
Android Bootcamp
Introduction to the Android NDK
Android Development
Using the android ndk - DroidCon Paris 2014
Using the Android Native Development Kit (NDK)
Cross-Platform Mobile Development in Visual Studio
Synapse india mobile apps update
Programming Android
Synapse india reviews on i phone and android os
Kirin - Making Single Page Web Apps with a Native UI
Industrial Training in Android Application
Android Internals
"JavaME + Android in action" CCT-CEJUG Dezembro 2008
Android Internals (This is not the droid you’re loking for...)
Android++ A Cross Platform Framework
Developing a mobile cross-platform library
Alternatives to Java for Android development
Ad

Recently uploaded (20)

PDF
Reach Out and Touch Someone: Haptics and Empathic Computing
PDF
Advanced methodologies resolving dimensionality complications for autism neur...
PDF
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
PDF
Machine learning based COVID-19 study performance prediction
PDF
Network Security Unit 5.pdf for BCA BBA.
PDF
Review of recent advances in non-invasive hemoglobin estimation
PDF
Mobile App Security Testing_ A Comprehensive Guide.pdf
PDF
Chapter 3 Spatial Domain Image Processing.pdf
PPTX
Big Data Technologies - Introduction.pptx
PDF
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
PDF
Encapsulation theory and applications.pdf
PDF
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
PDF
Encapsulation_ Review paper, used for researhc scholars
PDF
Approach and Philosophy of On baking technology
PPTX
Programs and apps: productivity, graphics, security and other tools
PDF
KodekX | Application Modernization Development
PDF
Unlocking AI with Model Context Protocol (MCP)
PDF
Building Integrated photovoltaic BIPV_UPV.pdf
PDF
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
PDF
Agricultural_Statistics_at_a_Glance_2022_0.pdf
Reach Out and Touch Someone: Haptics and Empathic Computing
Advanced methodologies resolving dimensionality complications for autism neur...
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
Machine learning based COVID-19 study performance prediction
Network Security Unit 5.pdf for BCA BBA.
Review of recent advances in non-invasive hemoglobin estimation
Mobile App Security Testing_ A Comprehensive Guide.pdf
Chapter 3 Spatial Domain Image Processing.pdf
Big Data Technologies - Introduction.pptx
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
Encapsulation theory and applications.pdf
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
Encapsulation_ Review paper, used for researhc scholars
Approach and Philosophy of On baking technology
Programs and apps: productivity, graphics, security and other tools
KodekX | Application Modernization Development
Unlocking AI with Model Context Protocol (MCP)
Building Integrated photovoltaic BIPV_UPV.pdf
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
Agricultural_Statistics_at_a_Glance_2022_0.pdf

Mobile Application Development with JUCE and Native API’s

  • 1. Mobile Application Development with JUCE and Native API’s Adam Wilson JUCE Summit 2015
  • 2. Creating mobile apps that mix JUCE components with native iOS or Android UI elements.
  • 3. Why? • JUCE is a cross-platform framework • Write once, run anywhere
  • 4. JUCE Components were designed for desktop apps, not for touch screen devices. Limited support for gestures Hard to get the feel right for common UI interactions
  • 6. E.g. ListBox component Needs adapting to respond to finger gestures
  • 7. E.g. ListBox component Needs adapting to respond to finger gestures Hard to get it to scroll smoothly when there is e.g. audio processing happening in the background
  • 9. Navigation E.g. swipe to move between pages
  • 10. Navigation E.g. swipe to move between pages Problem: Components grab mouse events
  • 11. Solution: Utilise native API’s Platform Language API Android Java Android API’s and Android Support Libraries iOS Objective-C / Swift Cocoa Touch
  • 12. Use Native API’s for: Scrollable Lists Navigation User input Database access
  • 13. Use JUCE for: Audio and data processing Custom graphics and animation (OpenGL) Custom or specialised GUI elements 
 e.g. MidiKeyboardComponent
  • 14. Advantages of this approach
  • 15. Advantages of this approach Familiar UI elements using each platform’s native idioms

  • 16. Advantages of this approach Familiar UI elements using each platform’s native idioms Smooth scrolling, gesture support 

  • 17. Advantages of this approach Familiar UI elements using each platform’s native idioms Smooth scrolling, gesture support Comprehensive toolkits for creating GUI’s: Xcode and Android Studio

  • 18. Advantages of this approach Familiar UI elements using each platform’s native idioms Smooth scrolling, gesture support Comprehensive toolkits for creating GUI’s: Xcode and Android Studio No need to code transitions and other animations - these are provided by the native API’s
  • 19. Advantages of this approach Familiar UI elements using each platform’s native idioms Smooth scrolling, gesture support Comprehensive toolkits for creating GUI’s: Xcode and Android Studio No need to code transitions and other animations - these are provided by the native API’s Use a local database e.g. SQLite, Couchbase Mobile, Firebase and connect directly to your UI

  • 21. Disadvantages of this approach Designing and coding part of your UI for each platform
 

  • 22. Disadvantages of this approach Designing and coding part of your UI for each platform Potentially complicated communication between languages:
 
 Java C++ Objective-C C++ Objective-C C++Swift
  • 23. How? There are two things to consider:
  • 24. How? There are two things to consider: 1. Mixing JUCE components with native UI
  • 25. How? There are two things to consider: 1. Mixing JUCE components with native UI 2. Passing data between C++ and Java, or C++ and Objective-C
  • 26. Disclaimer: Assume that most of the time we will only want to call C++ from the native UI code, not the other way round.
  • 27. Android + JUCE: UI We can now use Android Studio!
 (This turns out to be a nice IDE also for C++ development)
  • 28. Android + JUCE: UI Introjucer’s Android exporter generates a Java Activity class
  • 29. Android + JUCE: UI Introjucer’s Android exporter generates a Java Activity class The default activity is full screen
  • 30. Android + JUCE: UI Introjucer’s Android exporter generates a Java Activity class The default activity is full screen We want our JUCE component as part of a layout
  • 31. Android + JUCE: UI Introjucer’s Android exporter generates a Java Activity class The default activity is full screen We want our JUCE component as part of a layout So we need to do some modifications
  • 32. Android + JUCE: UI viewHolder = new ViewHolder (this);
 setContentView (viewHolder); In your default generated Activity class onCreate:
  • 33. Android + JUCE: UI viewHolder = new ViewHolder (this);
 setContentView (viewHolder); In your default generated Activity class onCreate: Would become something like: viewHolder = new ViewHolder (this);
 setContentView(R.layout.main_activity); LinearLayout juceViewContainer = (LinearLayout) findViewById(R.id.juce_view_container);
 juceViewContainer.addView(viewHolder);
  • 34. Android + JUCE: UI viewHolder = new ViewHolder (this);
 setContentView (viewHolder); In your default generated Activity class onCreate: Would become something like: viewHolder = new ViewHolder (this);
 setContentView(R.layout.main_activity); LinearLayout juceViewContainer = (LinearLayout) findViewById(R.id.juce_view_container);
 juceViewContainer.addView(viewHolder); main_activity.xml layout file
  • 35. Android + JUCE: UI viewHolder = new ViewHolder (this);
 setContentView (viewHolder); In your default generated Activity class onCreate: Would become something like: viewHolder = new ViewHolder (this);
 setContentView(R.layout.main_activity); LinearLayout juceViewContainer = (LinearLayout) findViewById(R.id.juce_view_container);
 juceViewContainer.addView(viewHolder); juce window within layout main_activity.xml layout file
  • 36. Android + JUCE: UI If we want to use the recent Android Support Libraries, which are necessary for Material Design style apps then we also need to change the base class (superclass) from Activity to AppCompatActivity:
 
 import android.support.v7.app.AppCompatActivity; //… public class JuceActivity extends AppCompatActivity { //… }
  • 38. Android + JUCE: Data Declare our JNI functions in Java and implement them in C++ The C++ functions could be getters, setters, actions etc.
  • 39. Android + JUCE: Data Sending data to C++:
  • 40. Android + JUCE: Data #if JUCE_ANDROID
 
 JUCE_JNI_CALLBACK (JUCE_ANDROID_ACTIVITY_CLASSNAME, setMessage, void, (JNIEnv* env, jclass, jstring message))
 {
 SharedResourcePointer<MainContentComponent> mainComponent;
 
 mainComponent->message = juceString (env, message);
 mainComponent->repaint();
 }
 
 #endif Sending data to C++:
  • 41. Android + JUCE: Data #if JUCE_ANDROID
 
 JUCE_JNI_CALLBACK (JUCE_ANDROID_ACTIVITY_CLASSNAME, setMessage, void, (JNIEnv* env, jclass, jstring message))
 {
 SharedResourcePointer<MainContentComponent> mainComponent;
 
 mainComponent->message = juceString (env, message);
 mainComponent->repaint();
 }
 
 #endif Sending data to C++: Android JNI Helper method converts jstring to JUCE String
  • 42. Android + JUCE: Data #if JUCE_ANDROID
 
 JUCE_JNI_CALLBACK (JUCE_ANDROID_ACTIVITY_CLASSNAME, setMessage, void, (JNIEnv* env, jclass, jstring message))
 {
 SharedResourcePointer<MainContentComponent> mainComponent;
 
 mainComponent->message = juceString (env, message);
 mainComponent->repaint();
 }
 
 #endif This is a global function Sending data to C++:
  • 43. Android + JUCE: Data Declare it in your Activity class: public static native void setMessage (String message);
  • 44. Android + JUCE: Data Declare it in your Activity class: public static native void setMessage (String message); JuceActivity.setMessage("My new message"); and then wherever you want to call that function, e.g.
  • 45. Android + JUCE: Data We might also want to pull data from our C++ code - e.g. a list of menu items
  • 46. Android + JUCE: Data Pulling data from C++ takes a little more work, e.g. in the case of a string: JUCE_JNI_CALLBACK (JUCE_ANDROID_ACTIVITY_CLASSNAME, getJsonDataBytes, jbyteArray, (JNIEnv* env, jclass))
 {
 SharedResourcePointer<MainContentComponent> mainComponent;
 String jsonData = mainComponent->data.toJson();
 
 int byteCount = jsonData.length();
 const jbyte* nativeString = reinterpret_cast<const jbyte*> ((const char *) jsonData.toUTF8());
 jbyteArray bytes = env->NewByteArray (byteCount);
 env->SetByteArrayRegion (bytes, 0, byteCount, nativeString);
 
 return bytes;
 }
  • 47. Android + JUCE: Data In your Activity class: public static String getJsonData()
 {
 return new String(getJsonDataBytes(), Charset.forName("UTF-8"));
 } private static native byte[] getJsonDataBytes();
  • 48. Android + JUCE: Data Thats it! If you do need to call Java from C++, you need to add your function definition to juce_android_JNIHelpers.h
 
 (I’ve not had to do this yet)
  • 49. iOS + JUCE: UI JUCE Window is a UIView Therefore we can add it as a subview to any other view in an iOS app
 E.g. a UIViewController
  • 50. iOS + JUCE: UI We need to modify the MainWindow class and make it an Objective-C++ file (.mm)
  • 51. iOS + JUCE: UI We need to modify the MainWindow class and make it an Objective-C++ file (.mm) Here we: 1. Create a UIWindow
  • 52. iOS + JUCE: UI MainWindow::MainWindow (String name) : DocumentWindow (name, Colours::lightgrey, DocumentWindow::allButtons) { UIWindow* window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
  • 53. iOS + JUCE: UI We need to modify the MainWindow class and make it an Objective-C++ file (.mm) Here we: 1. Create a UIWindow 2. Create a UIView
  • 54. iOS + JUCE: UI MainWindow::MainWindow (String name) : DocumentWindow (name, Colours::lightgrey, DocumentWindow::allButtons) { UIWindow* window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; UIView* juceView = [[UIView alloc] initWithFrame: [[UIScreen mainScreen] bounds]];
  • 55. iOS + JUCE: UI We need to modify the MainWindow class and make it an Objective-C++ file (.mm) Here we: 1. Create a UIWindow 2. Create a UIView 3. Add our Component to the UIView
  • 56. iOS + JUCE: UI MainWindow::MainWindow (String name) : DocumentWindow (name, Colours::lightgrey, DocumentWindow::allButtons) { UIWindow* window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; UIView* juceView = [[UIView alloc] initWithFrame: [[UIScreen mainScreen] bounds]]; MainWindow::addComponentToUIView (mainComponent.get(), juceView);
  • 57. iOS + JUCE: UI We need to modify the MainWindow class and make it an Objective-C++ file (.mm) Here we: 1. Create a UIWindow 2. Create a UIView 3. Add our Component to the UIView 4. E.g. add our JUCE UIView as a subview of a UIViewController
  • 58. iOS + JUCE: UI MainWindow::MainWindow (String name) : DocumentWindow (name, Colours::lightgrey, DocumentWindow::allButtons) { UIWindow* window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; UIView* juceView = [[UIView alloc] initWithFrame: [[UIScreen mainScreen] bounds]]; MainWindow::addComponentToUIView (mainComponent.get(), juceView); JuceViewController* juceViewController = // Subclass of UIViewController [[JuceViewController alloc] initWithContentView: juceView]; juceViewController.contentView = juceView; //…
  • 59. iOS + JUCE: UI void MainWindow::addComponentToUIView (Component& component, void* uiView) { component.addToDesktop (0, uiView); UIView* view = (UIView*) uiView; component.setVisible (true); component.setBounds (view.bounds.origin.x, view.bounds.origin.y, view.bounds.size.width, view.bounds.size.height); } Handy function:
  • 61. iOS + JUCE: Data We need to two layers One that is visible to C++, and the other that is visible to Objective-C. Lets call these DataController and Wrapper
  • 62. iOS + JUCE: Data DataController.h Wrapper.h DataController.cpp Wrapper.mm C++ Objective-C++
  • 63. iOS + JUCE: Data DataController.h Wrapper.h DataController.cpp Wrapper.mm JuceHeader.h
  • 64. iOS + JUCE: Data DataController.h Wrapper.h DataController.cpp Wrapper.mm Only basic C types exposed
  • 65. iOS + JUCE: Data /** * Methods to expose to Objective-C * Note that only basic C types are exposed */ struct DataController { DataController(); /** Get JSON string of all message data */ const char* getJsonData(); /** Set message and repaint MainContentComponent */ void setMessage (const char *title, const char* message); }; DataController.h
  • 66. iOS + JUCE: Data DataController.h Wrapper.h DataController.cpp Wrapper.mm C++ Objective-C++
  • 67. iOS + JUCE: Data #include "JuceHeader.h" #include "DataController.h" #include "MainComponent.h" #include "Data.h" void DataController::setMessage (const char *title, const char* message) { SharedResourcePointer<MainContentComponent> mainComponent; mainComponent->title = (String) title; mainComponent->message = (String) message; mainComponent->repaint(); } const char* DataController::getJsonData() { SharedResourcePointer<MainContentComponent> mainComponent; return mainComponent->data.toJson().toRawUTF8(); } DataController.cpp
  • 68. iOS + JUCE: Data DataController.h Wrapper.h DataController.cpp Wrapper.mm C++ Objective-C++
  • 69. iOS + JUCE: Data #import <Foundation/Foundation.h> @interface Wrapper : NSObject /** Set message and repaint JUCE MainContentComponent */ - (void)setMessage:(NSString*) message; /** Get Data as JSON String */ - (NSString*)getJsonData; @end Wrapper.h
  • 70. iOS + JUCE: Data DataController.h Wrapper.h DataController.cpp Wrapper.mm C++ Objective-C++
  • 71. iOS + JUCE: Data #import <Foundation/Foundation.h> #import "Wrapper.h" #import "DataController.h" @interface Wrapper () { DataController* wrapped; } @end @implementation Wrapper - (id)init { self = [super init]; if (self) { wrapped = new DataController(); if (!wrapped) self = nil; } return self; } Wrapper.mm http://philjordan.eu/article/mixing-objective-c-c++-and-objective-c++
  • 72. iOS + JUCE: Data #import <Foundation/Foundation.h> #import "Wrapper.h" #import "DataController.h" @interface Wrapper () { DataController* wrapped; } @end @implementation Wrapper - (id)init { self = [super init]; if (self) { wrapped = new DataController(); if (!wrapped) self = nil; } return self; } Wrapper.mm - (void)setMessage: (NSString*) message { const char* messageChar = [message UTF8String]; wrapped->setMessage(messageChar); } - (NSString*)getJsonData { const char* jsonCharPointer = wrapped->getJsonData(); NSString* jsonDataString = [NSString stringWithFormat:@“%s” jsonCharPointer]; return jsonDataString; } - (void)dealloc { delete wrapped; [super dealloc]; } @end http://philjordan.eu/article/mixing-objective-c-c++-and-objective-c++
  • 73. iOS + JUCE: Data #import <Foundation/Foundation.h> #import "Wrapper.h" #import "DataController.h" @interface Wrapper () { DataController* wrapped; } @end @implementation Wrapper - (id)init { self = [super init]; if (self) { wrapped = new DataController(); if (!wrapped) self = nil; } return self; } Wrapper.mm - (void)setMessage: (NSString*) message { const char* messageChar = [message UTF8String]; wrapped->setMessage(messageChar); } - (NSString*)getJsonData { const char* jsonCharPointer = wrapped->getJsonData(); NSString* jsonDataString = [NSString stringWithFormat:@“%s” jsonCharPointer]; return jsonDataString; } - (void)dealloc { delete wrapped; [super dealloc]; } @end http://philjordan.eu/article/mixing-objective-c-c++-and-objective-c++
  • 74. iOS + JUCE: Data Any Objective-C class can now call the exposed methods via
 #import "DataControllerWrapper.h"
  • 75. iOS + JUCE: Data Any Objective-C class can now call the exposed methods via
 This includes Swift - in that case it would be in e.g. MyJuceApp-Header.h
 (This is a special header file that allows us to expose Objective-C methods to Swift) I would recommend using Swift if possible #import "DataControllerWrapper.h"
  • 76. iOS + JUCE: Data If we want to call Objective-C (or Swift!) from C++ then we need to employ the PIMPL idiom This is the subject of another talk!
 See http://philjordan.eu/article/mixing-objective-c-c++-and-objective-c++
  • 77. Tying things together Seperate MainWindow class from Main.cpp Have an Objective-C++ version (e.g. iosWindow.h and iosWindow.mm) Then in your Main.cpp:
 
 
 #if JUCE_IOS #include "iosMainWindow.h" #else #include "MainWindow.h" #endif
  • 78. Thanks for listening! Example project source code available at: github.com/adamski/juce-native-navigation adam@codegarden.co.uk