@@ -31,23 +31,34 @@ PyMODINIT_FUNC initandroidembed(void) {
3131 (void ) Py_InitModule ("androidembed" , AndroidEmbedMethods );
3232}
3333
34- int file_exists ( const char * filename )
35- {
36- FILE * file ;
37- if ( file = fopen ( filename , "r" )) {
38- fclose ( file );
39- return 1 ;
34+ int asset_extract ( AAssetManager * am , char * src_file , char * dst_file ) {
35+ FILE * fhd = fopen ( dst_file , "wb" );
36+ if ( fhd == NULL ) {
37+ LOGW ( "Unable to open descriptor for %s (errno=%d:%s)" ,
38+ dst_file , errno , strerror ( errno ) );
39+ return - 1 ;
4040 }
41+
42+ AAsset * asset = AAssetManager_open (am , src_file , AASSET_MODE_BUFFER );
43+ if (asset == NULL ) {
44+ LOGW ("Unable to open asset %s" , src_file );
45+ return -1 ;
46+ }
47+
48+ off_t l = AAsset_getLength (asset );
49+ fwrite (AAsset_getBuffer (asset ),l , 1 , fhd );
50+ fclose (fhd );
51+ AAsset_close (asset );
52+
4153 return 0 ;
4254}
4355
44-
4556void android_main (struct android_app * state ) {
4657 app_dummy ();
4758 LOGI ("Starting minimal bootstrap." );
4859
4960 char * env_argument = NULL ;
50- FILE * fd ;
61+ int fd = -1 ;
5162
5263 LOGI ("Initialize Python for Android" );
5364 //env_argument = getenv("ANDROID_ARGUMENT");
@@ -57,30 +68,33 @@ void android_main(struct android_app* state) {
5768 Py_Initialize ();
5869 //PySys_SetArgv(argc, argv);
5970
60- /* ensure threads will work.
61- */
71+ // ensure threads will work.
6272 PyEval_InitThreads ();
6373
64- /* our logging module for android
65- */
74+ // our logging module for android
6675 initandroidembed ();
6776
68- /* inject our bootstrap code to redirect python stdin/stdout
69- * replace sys.path with our path
70- */
71- #if 0
72- PyRun_SimpleString (
73- "import sys, posix\n" \
74- "private = posix.environ['ANDROID_PRIVATE']\n" \
75- "argument = posix.environ['ANDROID_ARGUMENT']\n" \
76- "sys.path[:] = [ \n" \
77- " private + '/lib/python27.zip', \n" \
78- " private + '/lib/python2.7/', \n" \
79- " private + '/lib/python2.7/lib-dynload/', \n" \
80- " private + '/lib/python2.7/site-packages/', \n" \
81- " argument ]\n" )
82- #endif
83-
77+ // get the APK filename, and set it to ANDROID_APK_FN
78+ ANativeActivity * activity = state -> activity ;
79+ JNIEnv * env = NULL ;
80+ (* activity -> vm )-> AttachCurrentThread (activity -> vm , & env , 0 );
81+ jclass clazz = (* env )-> GetObjectClass (env , activity -> clazz );
82+ jmethodID methodID = (* env )-> GetMethodID (env , clazz , "getPackageCodePath" , "()Ljava/lang/String;" );
83+ jobject result = (* env )-> CallObjectMethod (env , activity -> clazz , methodID );
84+ const char * str ;
85+ jboolean isCopy ;
86+ str = (* env )-> GetStringUTFChars (env , (jstring )result , & isCopy );
87+ LOGI ("Looked up package code path: %s" , str );
88+ (* activity -> vm )-> DetachCurrentThread (activity -> vm );
89+
90+ // set some envs
91+ setenv ("ANDROID_APK_FN" , str , 1 );
92+ setenv ("ANDROID_INTERNAL_DATA_PATH" , state -> activity -> internalDataPath , 1 );
93+ setenv ("ANDROID_EXTERNAL_DATA_PATH" , state -> activity -> externalDataPath , 1 );
94+ LOGI ("Internal data path is: %s" , state -> activity -> internalDataPath );
95+ LOGI ("External data path is: %s" , state -> activity -> externalDataPath );
96+
97+ // inject our bootstrap code to redirect python stdin/stdout
8498 PyRun_SimpleString (
8599 "import sys, androidembed\n" \
86100 "class LogFile(object):\n" \
@@ -94,42 +108,62 @@ void android_main(struct android_app* state) {
94108 " self.buffer = lines[-1]\n" \
95109 " def flush(self):\n" \
96110 " return\n" \
97- "sys.stdout = sys.stderr = LogFile()\n" \
111+ "sys.stdout = sys.stderr = LogFile()\n" );
112+
113+ // let python knows where the python2.7 library is within the APK
114+ PyRun_SimpleString (
115+ "import sys, posix;" \
116+ "lib_path = '{}/assets/lib/python2.7/'.format(" \
117+ " posix.environ['ANDROID_APK_FN'])\n" \
118+ "sys.path[:] = [lib_path, '{}/site-packages'.format(lib_path)]\n" \
119+ "import os; from os.path import exists, join\n" \
120+ "config_path = join(posix.environ['ANDROID_INTERNAL_DATA_PATH'], 'python2.7', 'config')\n" \
121+ "if not exists(config_path): os.makedirs(config_path)\n" \
122+ "import sysconfig\n" \
123+ "sysconfig._get_makefile_filename = lambda: '{}/Makefile'.format(config_path)\n" \
124+ "sysconfig.get_config_h_filename = lambda: '{}/pyconfig.h'.format(config_path)\n" \
125+ );
126+
127+ // extract the Makefile, needed for sysconfig
128+ AAssetManager * am = state -> activity -> assetManager ;
129+ char dest_fn [512 ];
130+
131+ snprintf (dest_fn , 512 , "%s/python2.7/config/Makefile" , state -> activity -> internalDataPath );
132+ if (asset_extract (am , "lib/python2.7/config/Makefile" , dest_fn ) < 0 )
133+ return ;
134+
135+ snprintf (dest_fn , 512 , "%s/python2.7/config/pyconfig.h" , state -> activity -> internalDataPath );
136+ if (asset_extract (am , "include/python2.7/pyconfig.h" , dest_fn ) < 0 )
137+ return ;
138+
139+ // test import site
140+ PyRun_SimpleString (
98141 "import site; print site.getsitepackages()\n" \
99142 "print 'Android path', sys.path\n" \
100- "print 'Android kivy bootstrap done. __name__ is', __name__" );
143+ "print 'Android bootstrap done. __name__ is', __name__" );
101144
102145 /* run it !
103146 */
104- LOGI ("Run user program, change dir and execute main.py" );
105- //chdir(env_argument);
106-
107- /* search the initial main.py
108- */
109- char * main_py = "main.pyo" ;
110- if ( file_exists (main_py ) == 0 ) {
111- if ( file_exists ("main.py" ) )
112- main_py = "main.py" ;
113- else
114- main_py = NULL ;
115- }
116-
117- if ( main_py == NULL ) {
118- LOGW ("No main.pyo / main.py found." );
119- return ;
120- }
121-
122- fd = fopen (main_py , "r" );
123- if ( fd == NULL ) {
124- LOGW ("Open the main.py(o) failed" );
147+ LOGI ("Extract main.py from assets" );
148+ char main_fn [512 ];
149+ snprintf (main_fn , 512 , "%s/main.pyo" , state -> activity -> internalDataPath );
150+ if (asset_extract (am , "main.pyo" , main_fn ) < 0 )
125151 return ;
126- }
127152
128153 /* run python !
129154 */
130- PyRun_SimpleFile (fd , main_py );
155+ LOGI ("Run main.py >>>" );
156+ FILE * fhd = fopen (main_fn , "rb" );
157+ if (fhd == NULL ) {
158+ LOGW ("Cannot open main.pyo (errno=%d:%s)" , errno , strerror (errno ));
159+ return ;
160+ }
161+ int ret = PyRun_SimpleFile (fhd , main_fn );
162+ fclose (fhd );
163+ LOGI ("Run main.py (ret=%d) <<<" , ret );
131164
132165 if (PyErr_Occurred () != NULL ) {
166+ LOGW ("An error occured." );
133167 PyErr_Print (); /* This exits with the right code if SystemExit. */
134168 if (Py_FlushLine ())
135169 PyErr_Clear ();
@@ -138,7 +172,6 @@ void android_main(struct android_app* state) {
138172 /* close everything
139173 */
140174 Py_Finalize ();
141- fclose (fd );
142175
143176 LOGW ("Python for android ended." );
144177}
0 commit comments