Boxed
Proof of concept using SDL2 project with shared code that works on Linux, Android and iOS.
This repository was created for personal study purposes, so you won't find proper replication guidelines. Feel free to ask any questions if you want to know more about the process.
Also keep in mind that common/src/main.c
contains references to all three environments via C macros. In a maintainable code base this should be abstracted away to their respective platform folders for readability reasons. The intent of the proof of concept was to show that a shared C code base was possible, so designs decisions like this were permitted as long as it made the writing of the code easier and faster.
Download and Build SDL
- Clone SDL repository as a sibling folder to
boxed
:
git clone git@github.com:libsdl-org/SDL.git
- Checkout SDL2 branch:
git checkout SDL2
- Build it:
./configure
make -j8
Download and Build SDL_image
- Clone SDL_image repository as a sibling folder to
boxed
:
git clone git@github.com:libsdl-org/SDL_image.git
- Download external libraries:
./external/download.sh
- Build it:
./configure
make -j8
VS Code Include Path
Add ../SDL/include
and ../SDL_image
to the workspace setting C_Cpp.default.includePath
.
The Common Folder
This folder contains the shared assets between all the target platforms.
src/main.c
(SDL2 code exercising rendering, image loading, audio playback and a HTTP request)assets/enemy.png
(sprite texture)assets/hit.wav
(sound effect)
Build and Run on Linux
cd linux
./build.sh
cd dist
./boxed
Copy Android Template from SDL Repo
mkdir android/
cp -R ../SDL/android-project/* android
Build SDL2 and SDL2_image Android Prefabs
(check your Android Home and NDK Home dirs)
cd ../SDL
ANDROID_HOME=~/Android/Sdk ANDROID_NDK_HOME=~/Android/Sdk/ndk/21.4.7075529 ./build-scripts/android-prefab.sh
cd ../SDL_image
sdl_build_root=../SDL/build-android-prefab ANDROID_HOME=~/Android/Sdk ANDROID_NDK_HOME=~/Android/Sdk/ndk/21.4.7075529 ./build-scripts/android-prefab.sh
Adapt Android Template
gradle.properties
: Use prefab version 2
android.prefabVersion=2.0.0
- Delete Java Classes (they will be available inside the prefab jars)
rm -rf android/app/src/main/java/org/
-
app/build.gradle
-
Clean referentes to Cmake build
-
Clean buildAsLibrary variant
-
Change applicationId
-
Change minSdkVersion to 24
-
Add prefab dependencies (check versions looking for newer releases):
dependencies { implementation 'com.android.ndk.thirdparty:libpng:1.6.37-alpha-1' implementation files('../../../SDL/build-android-prefab/prefab-2.27.0/SDL2-2.27.0.aar') implementation files('../../../SDL_image/build-android-prefab/prefab-2.7.0/SDL2_image-2.7.0.aar') implementation fileTree(include: ['*.jar'], dir: 'libs') }
-
Enable prefab (right below
lintOptions
)buildFeatures { prefab true }
-
-
AndroidManifest.xml
-
Change package
-
Change activity android:name attribute
-
Add permission for INTERNET access:
<uses-permission android:name="android.permission.INTERNET" />
-
-
Symlink assets:
mkdir android/app/src/main/assets
ln -s $PWD/common/assets $PWD/android/app/src/main/assets/assets
(the resulting folder will be android/app/src/main/assets/assets)
-
Change app name inside
android/app/src/main/res/values/strings.xml
-
Create Java classes
Boxed
andHTTPRequests
in packageandroid/app/src/main/java/dev/samuel/boxed
-
Delete all
CmakeLists.txt
files -
Enable
c++-shared
STL insideApplication.mk
APP_STL := c++_shared
-
Adapt
app/jni/src/Android.mk
-
Remove
SDL_PATH
andLOCAL_C_INCLUDES
-
Adapt
LOCAL_SRC_FILES
(common/main.c
) -
Add
SDL2_image png16
toLOCAL_SHARED_LIBRARIES
-
Remove everything but
-llog
fromLOCAL_LDLIBS
-
Add prefab calls at the end of the file:
$(call import-module,prefab/SDL2) $(call import-module,prefab/SDL2_image) $(call import-module,prefab/png16)
-
-
Symlink C code:
ln -s $PWD/common/src $PWD/android/app/jni/src/common
Running Android App
- Check if you have a simulator or device running (how to run one of them is outside the scope of this README)
adb devices
- Run it
cd android/
./gradlew installDebug
- Checking logs
adb logcat | grep Boxed
Creating the Xcode Project
- Select the
iOS
tab. - Select
Game
. - Fill in Product Name.
- Select the Team.
- Keep language as Objective-C.
- Keep Game Technology as Metal.
- Untick Tests.
- Untick "Create Git repository on my Mac".
- Delete everything except Assets and LaunchScreen.
- Change deployment target to a reasonable value (e.g. 12).
- Clone both SDL and SDL_image as siblings to this repository folder.
- Checkout the
SDL2
branch on both repositories. - Add both
SDL/Xcode/SDL/SDL.xcodeproj
andSDL_image/Xcode/SDL_image.xcodeproj
to the project. - Clear the "Main storyboard file base name" property (Main Target > Info Tab > Custom iOS Target Properties).
- Add both include folders (SDL > Public Headers and SDL_image root folder) to the target's Build Settings > Header Search Path.
- Do the same for the SDL folder on the SDL_image Framework target header search path.
- Add both libraries (SDL > SDL2.framework from Framework-IOS and SDL_image > SDL2_image.framework) to the Build Phases > Link Binary With Libraries section.
- Mark both frameworks to be embedded and signed on General > Frameworks, Libraries and Embedded Content.
- Expand SDL > Library Source > main > uikit and drag SDL_uikit_main.c to the main game group.
- Add a reference to
main.c
from thecommon/src
folder. - Add a reference to
common/assets
as well inside the main project group.
Useful Commands to Remember
- Related to loading shared libraries on Linux:
readelf -d linux/dist/boxed
sudo lsof | grep boxed | grep SDL
objdump -p linux/dist/boxed
LD_LIBRARY_PATH=. ./boxed