Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

kivy-ios runs in simulator but not on physical iPhone #567

Closed
kgeoffrey opened this issue Dec 3, 2020 · 9 comments
Closed

kivy-ios runs in simulator but not on physical iPhone #567

kgeoffrey opened this issue Dec 3, 2020 · 9 comments

Comments

@kgeoffrey
Copy link

I am trying to run a kivy application on my iPhone. So far the simulator builds and runs the app and while the build also succeeds for the physical iPhone, when I try to open the application I get the following error message:

2020-12-03 21:35:29.101148+0100 testapp[913:114429] Available orientation: KIVY_ORIENTATION=LandscapeLeft LandscapeRight Portrait PortraitUpsideDown
2020-12-03 21:35:29.101196+0100 testapp[913:114429] Initializing python
2020-12-03 21:35:29.177107+0100 testapp[913:114429] Running main.py: /private/var/containers/Bundle/Application/C5855782-7DE8-4A5D-8AA4-FED75BCA257E/testapp.app/YourApp/main.pyc
[INFO ] [Kivy ] v2.0.0rc1, git-Unknown, 20200721
[INFO ] [Kivy ] Installed at "/private/var/containers/Bundle/Application/C5855782-7DE8-4A5D-8AA4-FED75BCA257E/testapp.app/lib/python3.8/site-packages/kivy/init.py"
[INFO ] [Python ] v3.8.2 (default, Jul 21 2020, 20:32:31)
[Clang 11.0.3 (clang-1103.0.32.62)]
[INFO ] [Python ] Interpreter at "/private/var/containers/Bundle/Application/C5855782-7DE8-4A5D-8AA4-FED75BCA257E/testapp.app/testapp"
[INFO ] [Factory ] 184 symbols loaded
[INFO ] [Image ] Providers: (img_imageio, img_tex, img_dds, img_sdl2, img_ffpyplayer, img_gif, img_pil ignored)
[CRITICAL] [App ] Unable to get any Image provider, abort.

Thanks

@misl6
Copy link
Member

misl6 commented Dec 6, 2020

Hi @kgeoffrey can you please share some details about your environment?

@kgeoffrey
Copy link
Author

Hey @misl6

I am using a venv with py3.
I thought that it might be the same issue as #556, as pillow would not built. I have since downgraded Xcode to 11.2.1, wiped and cloned the kivy-ios repo. Even though the the build does not fail I get the same error when I try to build on a physical device.

I am running this on MacOS Catalina 10.15.5

@misl6
Copy link
Member

misl6 commented Dec 6, 2020

How about the physical device?

Also, can you share the Xcode project or part of it (i.e the main.m part)?

@kgeoffrey
Copy link
Author

I have tried it on an iPhone SE second gen, iOS 14.1 (with Xcode 12), and an iPhone 6S with iOS 13

This is main.m:

`
//
// main.m
// testapp
//

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#include "Python.h"
#include "/Users/geoffreykasenbacher/test_venv/kivy-ios/dist/include/common/sdl2/SDL_main.h"
#include <dlfcn.h>

void export_orientation();
void load_custom_builtin_importer();

int main(int argc, char *argv[]) {
int ret = 0;

NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

// Change the executing path to YourApp
chdir("YourApp");

// Special environment to prefer .pyo, and don't write bytecode if .py are found
// because the process will not have a write attribute on the device.
putenv("PYTHONOPTIMIZE=2");
putenv("PYTHONDONTWRITEBYTECODE=1");
putenv("PYTHONNOUSERSITE=1");
putenv("PYTHONPATH=.");
putenv("PYTHONUNBUFFERED=1");
putenv("LC_CTYPE=UTF-8");
// putenv("PYTHONVERBOSE=1");
// putenv("PYOBJUS_DEBUG=1");

// Kivy environment to prefer some implementation on iOS platform
putenv("KIVY_BUILD=ios");
putenv("KIVY_NO_CONFIG=1");
putenv("KIVY_NO_FILELOG=1");
putenv("KIVY_WINDOW=sdl2");
putenv("KIVY_IMAGE=imageio,tex,gif");
putenv("KIVY_AUDIO=sdl2");
putenv("KIVY_GL_BACKEND=sdl2");

// IOS_IS_WINDOWED=True disables fullscreen and then statusbar is shown
putenv("IOS_IS_WINDOWED=False");

#ifndef DEBUG
putenv("KIVY_NO_CONSOLELOG=1");
#endif

// Export orientation preferences for Kivy
export_orientation();

NSString * resourcePath = [[NSBundle mainBundle] resourcePath];
NSString *python_home = [NSString stringWithFormat:@"PYTHONHOME=%@", resourcePath, nil];
putenv((char *)[python_home UTF8String]);

NSString *python_path = [NSString stringWithFormat:@"PYTHONPATH=%@:%@/lib/python3.8/:%@/lib/python3.8/site-packages:.", resourcePath, resourcePath, resourcePath, nil];
putenv((char *)[python_path UTF8String]);

NSString *tmp_path = [NSString stringWithFormat:@"TMP=%@/tmp", resourcePath, nil];
putenv((char *)[tmp_path UTF8String]);

NSLog(@"Initializing python");
Py_Initialize();

wchar_t** python_argv = PyMem_RawMalloc(sizeof(wchar_t *) *argc);
for (int i = 0; i < argc; i++)
    python_argv[i] = Py_DecodeLocale(argv[i], NULL);
PySys_SetArgv(argc, python_argv);

// If other modules are using the thread, we need to initialize them before.
PyEval_InitThreads();

// Add an importer for builtin modules
load_custom_builtin_importer();

// Search and start main.py

#define MAIN_EXT @"pyc"

const char * prog = [
    [[NSBundle mainBundle] pathForResource:@"YourApp/main" ofType:MAIN_EXT] cStringUsingEncoding:
    NSUTF8StringEncoding];
NSLog(@"Running main.py: %s", prog);
FILE* fd = fopen(prog, "r");
if ( fd == NULL ) {
    ret = 1;
    NSLog(@"Unable to open main.py, abort.");
} else {
    ret = PyRun_SimpleFileEx(fd, prog, 1);
    if (ret != 0)
        NSLog(@"Application quit abnormally!");
}

Py_Finalize();
NSLog(@"Leaving");

[pool release];

// Look like the app still runs even when we left here.
exit(ret);
return ret;

}

// This method reads the available orientations from the Info.plist file and
// shares them via an environment variable. Kivy will automatically set the
// orientation according to this environment value, if it exists. To restrict
// the allowed orientation, please see the comments inside.
void export_orientation() {
NSDictionary *info = [[NSBundle mainBundle] infoDictionary];
NSArray *orientations = [info objectForKey:@"UISupportedInterfaceOrientations"];

// Orientation restrictions
// ========================
// Comment or uncomment blocks 1-3 in order the limit orientation support

// 1. Landscape only
// NSString *result = [[NSString alloc] initWithString:@"KIVY_ORIENTATION=LandscapeLeft LandscapeRight"];

// 2. Portrait only
// NSString *result = [[NSString alloc] initWithString:@"KIVY_ORIENTATION=Portrait PortraitUpsideDown"];

// 3. All orientations
NSString *result = [[NSString alloc] initWithString:@"KIVY_ORIENTATION="];
for (int i = 0; i < [orientations count]; i++) {
    NSString *item = [orientations objectAtIndex:i];
    item = [item substringFromIndex:22];
    if (i > 0)
        result = [result stringByAppendingString:@" "];
    result = [result stringByAppendingString:item];
}
// ========================

putenv((char *)[result UTF8String]);
NSLog(@"Available orientation: %@", result);

}

void load_custom_builtin_importer() {
static const char *custom_builtin_importer =
"import sys, imp, types\n"
"from os import environ\n"
"from os.path import exists, join\n"
"try:\n"
" # python 3\n"
" import _imp\n"
" EXTS = imp.extension_suffixes()\n"
" sys.modules['subprocess'] = types.ModuleType(name='subprocess')\n"
" sys.modules['subprocess'].PIPE = None\n"
" sys.modules['subprocess'].STDOUT = None\n"
" sys.modules['subprocess'].DEVNULL = None\n"
" sys.modules['subprocess'].CalledProcessError = Exception\n"
" sys.modules['subprocess'].check_output = None\n"
"except ImportError:\n"
" EXTS = ['.so']\n"
"# Fake redirection to supress console output\n"
"if environ.get('KIVY_NO_CONSOLE', '0') == '1':\n"
" class fakestd(object):\n"
" def write(self, *args, **kw): pass\n"
" def flush(self, *args, **kw): pass\n"
" sys.stdout = fakestd()\n"
" sys.stderr = fakestd()\n"
"# Custom builtin importer for precompiled modules\n"
"class CustomBuiltinImporter(object):\n"
" def find_module(self, fullname, mpath=None):\n"
" # print(f'find_module() fullname={fullname} mpath={mpath}')\n"
" if '.' not in fullname:\n"
" return\n"
" if not mpath:\n"
" return\n"
" part = fullname.rsplit('.')[-1]\n"
" for ext in EXTS:\n"
" fn = join(list(mpath)[0], '{}{}'.format(part, ext))\n"
" # print('find_module() {}'.format(fn))\n"
" if exists(fn):\n"
" return self\n"
" return\n"
" def load_module(self, fullname):\n"
" f = fullname.replace('.', '
')\n"
" mod = sys.modules.get(f)\n"
" if mod is None:\n"
" # print('LOAD DYNAMIC', f, sys.modules.keys())\n"
" try:\n"
" mod = imp.load_dynamic(f, f)\n"
" except ImportError:\n"
" # import traceback; traceback.print_exc();\n"
" # print('LOAD DYNAMIC FALLBACK', fullname)\n"
" mod = imp.load_dynamic(fullname, fullname)\n"
" sys.modules[fullname] = mod\n"
" return mod\n"
" return mod\n"
"sys.meta_path.insert(0, CustomBuiltinImporter())";
PyRun_SimpleString(custom_builtin_importer);
}

`

@misl6
Copy link
Member

misl6 commented Dec 24, 2020

Sorry for the delay, can you please describe your installation and building procedure?
Also, how you created the Xcode project ?

@misl6
Copy link
Member

misl6 commented Mar 27, 2021

Closing due to inactivity, feel free to re-open if it still needed.

@misl6 misl6 closed this as completed Mar 27, 2021
@itivoni123
Copy link

Hi,
I'm getting the same error @misl6 like @kgeoffrey

Can you please help me?

Thanks

@itivoni123
Copy link

itivoni123 commented Jan 2, 2023

@misl6 here is my main.m
//
// main.m
// icalc
//

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#include "Python.h"
#include "/PATH/kivy_mobile/calc/dist/include/common/sdl2/SDL_main.h"
#include <dlfcn.h>

void export_orientation(void);
void load_custom_builtin_importer(void);

int main(int argc, char *argv[]) {
int ret = 0;

NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

// Change the executing path to YourApp
chdir("YourApp");

// Special environment to prefer .pyo, and don't write bytecode if .py are found
// because the process will not have a write attribute on the device.
putenv("PYTHONOPTIMIZE=2");
putenv("PYTHONDONTWRITEBYTECODE=1");
putenv("PYTHONNOUSERSITE=1");
putenv("PYTHONPATH=.");
putenv("PYTHONUNBUFFERED=1");
putenv("LC_CTYPE=UTF-8");
// putenv("PYTHONVERBOSE=1");
// putenv("PYOBJUS_DEBUG=1");

// Kivy environment to prefer some implementation on iOS platform
putenv("KIVY_BUILD=ios");
putenv("KIVY_WINDOW=sdl2");
putenv("KIVY_IMAGE=imageio,tex,gif,sdl2");
putenv("KIVY_AUDIO=sdl2");
putenv("KIVY_GL_BACKEND=sdl2");

// IOS_IS_WINDOWED=True disables fullscreen and then statusbar is shown
putenv("IOS_IS_WINDOWED=False");

#ifndef DEBUG
putenv("KIVY_NO_CONSOLELOG=1");
#endif

// Export orientation preferences for Kivy
export_orientation();

NSString * resourcePath = [[NSBundle mainBundle] resourcePath];
NSString *python_home = [NSString stringWithFormat:@"PYTHONHOME=%@", resourcePath, nil];
putenv((char *)[python_home UTF8String]);

NSString *python_path = [NSString stringWithFormat:@"PYTHONPATH=%@:%@/lib/python3.9/:%@/lib/python3.9/site-packages:.", resourcePath, resourcePath, resourcePath, nil];
putenv((char *)[python_path UTF8String]);

NSString *tmp_path = [NSString stringWithFormat:@"TMP=%@/tmp", resourcePath, nil];
putenv((char *)[tmp_path UTF8String]);

NSLog(@"Initializing python");
Py_Initialize();

wchar_t** python_argv = PyMem_RawMalloc(sizeof(wchar_t *) *argc);
for (int i = 0; i < argc; i++)
    python_argv[i] = Py_DecodeLocale(argv[i], NULL);
PySys_SetArgv(argc, python_argv);

// If other modules are using the thread, we need to initialize them before.
/*PyEval_InitThreads();*/

// Add an importer for builtin modules
load_custom_builtin_importer();

// Search and start main.py

#define MAIN_EXT @"py"

const char * prog = [
    [[NSBundle mainBundle] pathForResource:@"YourApp/main" ofType:MAIN_EXT] cStringUsingEncoding:
    NSUTF8StringEncoding];
NSLog(@"Running main.py: %s", prog);
FILE* fd = fopen(prog, "r");
if ( fd == NULL ) {
    ret = 1;
    NSLog(@"Unable to open main.py, abort.");
} else {
    ret = PyRun_SimpleFileEx(fd, prog, 1);
    if (ret != 0)
        NSLog(@"Application quit abnormally!");
}

Py_Finalize();
NSLog(@"Leaving");

[pool release];

// Look like the app still runs even when we left here.
exit(ret);
return ret;

}

// This method reads the available orientations from the Info.plist file and
// shares them via an environment variable. Kivy will automatically set the
// orientation according to this environment value, if it exists. To restrict
// the allowed orientation, please see the comments inside.
void export_orientation() {
NSDictionary *info = [[NSBundle mainBundle] infoDictionary];
NSArray *orientations = [info objectForKey:@"UISupportedInterfaceOrientations"];

// Orientation restrictions
// ========================
// Comment or uncomment blocks 1-3 in order the limit orientation support

// 1. Landscape only
// NSString *result = [[NSString alloc] initWithString:@"KIVY_ORIENTATION=LandscapeLeft LandscapeRight"];

// 2. Portrait only
// NSString *result = [[NSString alloc] initWithString:@"KIVY_ORIENTATION=Portrait PortraitUpsideDown"];

// 3. All orientations
NSString *result = [[NSString alloc] initWithString:@"KIVY_ORIENTATION="];
for (int i = 0; i < [orientations count]; i++) {
    NSString *item = [orientations objectAtIndex:i];
    item = [item substringFromIndex:22];
    if (i > 0)
        result = [result stringByAppendingString:@" "];
    result = [result stringByAppendingString:item];
}
// ========================

putenv((char *)[result UTF8String]);
NSLog(@"Available orientation: %@", result);

}

void load_custom_builtin_importer() {
static const char *custom_builtin_importer =
"import sys, imp, types\n"
"from os import environ\n"
"from os.path import exists, join\n"
"try:\n"
" # python 3\n"
" import _imp\n"
" EXTS = imp.extension_suffixes()\n"
" sys.modules['subprocess'] = types.ModuleType(name='subprocess')\n"
" sys.modules['subprocess'].PIPE = None\n"
" sys.modules['subprocess'].STDOUT = None\n"
" sys.modules['subprocess'].DEVNULL = None\n"
" sys.modules['subprocess'].CalledProcessError = Exception\n"
" sys.modules['subprocess'].check_output = None\n"
"except ImportError:\n"
" EXTS = ['.so']\n"
"# Fake redirection to supress console output\n"
"if environ.get('KIVY_NO_CONSOLE', '0') == '1':\n"
" class fakestd(object):\n"
" def write(self, *args, **kw): pass\n"
" def flush(self, *args, **kw): pass\n"
" sys.stdout = fakestd()\n"
" sys.stderr = fakestd()\n"
"# Custom builtin importer for precompiled modules\n"
"class CustomBuiltinImporter(object):\n"
" def find_module(self, fullname, mpath=None):\n"
" # print(f'find_module() fullname={fullname} mpath={mpath}')\n"
" if '.' not in fullname:\n"
" return\n"
" if not mpath:\n"
" return\n"
" part = fullname.rsplit('.')[-1]\n"
" for ext in EXTS:\n"
" fn = join(list(mpath)[0], '{}{}'.format(part, ext))\n"
" # print('find_module() {}'.format(fn))\n"
" if exists(fn):\n"
" return self\n"
" return\n"
" def load_module(self, fullname):\n"
" f = fullname.replace('.', '
')\n"
" mod = sys.modules.get(f)\n"
" if mod is None:\n"
" # print('LOAD DYNAMIC', f, sys.modules.keys())\n"
" try:\n"
" mod = imp.load_dynamic(f, f)\n"
" except ImportError:\n"
" # import traceback; traceback.print_exc();\n"
" # print('LOAD DYNAMIC FALLBACK', fullname)\n"
" mod = imp.load_dynamic(fullname, fullname)\n"
" sys.modules[fullname] = mod\n"
" return mod\n"
" return mod\n"
"sys.meta_path.insert(0, CustomBuiltinImporter())";
PyRun_SimpleString(custom_builtin_importer);
}

@misl6
Copy link
Member

misl6 commented Jan 5, 2023

Hi @itivoni123 ,
For a faster interaction, can you please ping me on Discord? (We will report back here if it's a bug and needs to be addressed)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants