@@ -31,23 +31,34 @@ PyMODINIT_FUNC initandroidembed(void) {
31
31
(void ) Py_InitModule ("androidembed" , AndroidEmbedMethods );
32
32
}
33
33
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 ;
40
40
}
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
+
41
53
return 0 ;
42
54
}
43
55
44
-
45
56
void android_main (struct android_app * state ) {
46
57
app_dummy ();
47
58
LOGI ("Starting minimal bootstrap." );
48
59
49
60
char * env_argument = NULL ;
50
- FILE * fd ;
61
+ int fd = -1 ;
51
62
52
63
LOGI ("Initialize Python for Android" );
53
64
//env_argument = getenv("ANDROID_ARGUMENT");
@@ -57,30 +68,33 @@ void android_main(struct android_app* state) {
57
68
Py_Initialize ();
58
69
//PySys_SetArgv(argc, argv);
59
70
60
- /* ensure threads will work.
61
- */
71
+ // ensure threads will work.
62
72
PyEval_InitThreads ();
63
73
64
- /* our logging module for android
65
- */
74
+ // our logging module for android
66
75
initandroidembed ();
67
76
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
84
98
PyRun_SimpleString (
85
99
"import sys, androidembed\n" \
86
100
"class LogFile(object):\n" \
@@ -94,42 +108,62 @@ void android_main(struct android_app* state) {
94
108
" self.buffer = lines[-1]\n" \
95
109
" def flush(self):\n" \
96
110
" 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 (
98
141
"import site; print site.getsitepackages()\n" \
99
142
"print 'Android path', sys.path\n" \
100
- "print 'Android kivy bootstrap done. __name__ is', __name__" );
143
+ "print 'Android bootstrap done. __name__ is', __name__" );
101
144
102
145
/* run it !
103
146
*/
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 )
125
151
return ;
126
- }
127
152
128
153
/* run python !
129
154
*/
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 );
131
164
132
165
if (PyErr_Occurred () != NULL ) {
166
+ LOGW ("An error occured." );
133
167
PyErr_Print (); /* This exits with the right code if SystemExit. */
134
168
if (Py_FlushLine ())
135
169
PyErr_Clear ();
@@ -138,7 +172,6 @@ void android_main(struct android_app* state) {
138
172
/* close everything
139
173
*/
140
174
Py_Finalize ();
141
- fclose (fd );
142
175
143
176
LOGW ("Python for android ended." );
144
177
}
0 commit comments