Running objective-c code on Android devices

The beginning of the story

A project written in cocos2d came to me for revision. A game for children in which you need to collect puzzles and learn words. Work is like work, but the main problem was that before me a certain girl from India worked on the project. And then I began a very fun period. An example of what I had to look at, what to do and how it all ended, will be under the cut.

Indocode provides mood for the whole day
- (void)imagePickerController:(UIImagePickerController *)pickerView didFinishPickingMediaWithInfo:(NSDictionary *)info
    [[NSUserDefaults standardUserDefaults]setObject:nil forKey:@"cameraImage"];
    UIImage *resiZedImage=[info objectForKey:UIImagePickerControllerOriginalImage];
    UIInterfaceOrientation interfaceOrientation = [[UIApplication sharedApplication] statusBarOrientation];
    if (UIInterfaceOrientationIsPortrait(interfaceOrientation))
        resiZedImage=[self ImageResize:resiZedImage];
        resiZedImage=[self imageByCropping:resiZedImage toRect:CGRectMake(800,300,1006,1258)];
    [[NSUserDefaults standardUserDefaults]setInteger:preDefined6 forKey:imageIndex];
    [[NSUserDefaults standardUserDefaults]setObject:[NSData dataWithData:UIImagePNGRepresentation(resiZedImage)] forKey:@"cameraImage"];
    [[NSUserDefaults standardUserDefaults]synchronize];
    [self performSelector:@selector(dismissCameraView:) withObject:pickerView afterDelay:1.0];
    [[CCDirector sharedDirector]replaceScene:[PlayScene scene]];
	self = [super init];
		camera = YES;
		NSData* imageData = [[NSUserDefaults standardUserDefaults] objectForKey:@"cameraImage"];
		UIImage* cameraImage = [[[UIImage alloc] initWithData:imageData]autorelease];
  	 	 puzzleObject=[CCSprite spriteWithCGImage:cameraImage.CGImage key:nil];
return self;

However, the post is not about errors that I had to fix, but about a completely different problem.
After several months of work on the project, when the main problems were resolved, the customer asked to build a build for his Android device. Then there was an amazing conversation about what the first developer was supposed to write for cocos2d-x and the application should easily run on any device. I had to solve the problem already and my choice fell on Apportable.

Actually the topic

According to the official website, the Apportable SDK is a system that allows you to run the same xCode project on iOS and Android devices. First of all, this applies to games written in cocos2d. There are problems with porting some Core Core frameworks.
Our game was written practically on pure coconut and only in two places were UIKit elements used.
Well then. Let's get started.

The first thing to do is install the SDK on Mac. To do this, following the instructions on the site, you just need to enter in the terminal

   (echo; echo PATH=~/.apportable/SDK/bin:$PATH) >> ~/.bash_profile; source ~/.bash_profile

The SDK requires about 2GB of free disk space and installed xCode 5.

While all this is downloading, you can add the necessary code to our project.
First, set the screen emulation mode. There are several options.
For example:
UIScreenIPhone3GEmulationMode - used if your application does not support graphics from retina devices. The virtual screen size is 320px / 480px, scale - 1.0
UIScreenScaledAspectFitEmulationMode - stretches your application according to the screen size of the Android device. Uses no retina graphics.
UIScreenBestEmulatedMode - Stretches your application in accordance with the screen size of the Android device. Uses the most appropriate graphics. For this mode to work correctly, there should be graphics for all iPhone and iPad screens. Otherwise, it may not look best at all.

int main(int argc, char *argv[]) {
    @autoreleasepool {
#ifdef ANDROID
        [UIScreen mainScreen].currentMode = [UIScreenMode emulatedMode:UIScreenAspectFitEmulationMode];
        int retVal = UIApplicationMain(argc, argv, nil, @"AppController");
        return retVal;

All options
typedef NS_ENUM(NSUInteger, UIScreenEmulationMode) {
    UIScreenBestEmulatedMode = UIScreenBestEmulationMode,

The next thing that had to be redone was the position of the elements.
[item setPosition:ccp(400, 600)]; 

on the
[item setPosition:ccp(puzzle.contentSize.width * 0.2, puzzle.contentSize.height * 0.772)];

The same thing when tracking clicks.

After that, go to the terminal with the project folder in the terminal and enter:
    apportable load

This command will create an apk file, download it to the connected device, install and run. Ideally. He is not always. I will not consider file linking errors, they are very individual. However, there is a situation when apportable does not see any particular device. At the office of 7 devices on which I tested the application, I could not install on 3.
What should I do in this case? Everything is very simple. Apportable first creates an apk file and only then tries to download it to the device. So this file is somewhere. More specifically, here:

The apk file is in this folder and you can simply transfer it to the device and install it. For this, I used the Android File Transfer application (in the poppy out of the box you can not access the memory of Android devices).

All? Profit? Unfortunately not.
There is a problem with the camera. The camera called up, took a photo, but when the confirmation button was pressed, the application crashed. The problem was not googled and promised to bring big problems, but ... Help came from our android developers. I found out what the manifest and permits are.
What is this? For iOS developers
An analogue of our info.plist. The manifest contains the basic settings, all rights and configuration.

So. After creating the build using apportable, the ProjectName.aproj folder appeared in the project directory. This folder contains configuration files and files that are not compiled (for example, resources).
We are interested in the configuration.json file. In it, you can change the project compilation settings for android. For example, add permissions. Camera requires write permissions.
And change the line
    "FEATURES": ["opengles2","landscape"]

on the
    "FEATURES": ["opengles2","landscape","write_external_storage"]

magically solved the problem.

There is also a nuance with the localization of the application name on the device screen. For each language, add the strings.xml file and put it in the ProjectName / java / res / values- [lang_description] folder

Localization name

And add to configuration.json:
//A list of java resource directories
    "java_res_dirs": ["java/res"]

Last few points:

  • There are a lot of screen racks on Android devices, and in some places I had to use the following inserts:
    Hidden text
    #ifdef ANDROID
                CGRect frame = [UIScreen mainScreen].applicationFrame;//1.7031 - pad  1.778 - phone
                CGFloat ratio = frame.size.height / frame.size.width;      
                    if (ratio < 1.72)
                        x = 16;
                        x = 29;
  • If the “portrait” flag is not in the configuration.json file, and the Device Orientation in the xCode settings of the project has a checkmark next to “Portrait”, then portrait orientation will be supported. Be careful.
  • Official documentation
  • Apportable has added many system frameworks. The official documentation contains little information about this. New .h files with new methods available for android can be found in the
    /Users/username/.apportable/SDK/sysroot/System/Library folder

Also popular now: