Skip to content

Commit 044568b

Browse files
committed
Adapt webview's bootstrap c/java code to new python build system
Note: All this work is based on previous work done on sdl2 bootstrap
1 parent 2ee7957 commit 044568b

File tree

4 files changed

+163
-85
lines changed

4 files changed

+163
-85
lines changed

pythonforandroid/bootstraps/webview/build/jni/application/src/start.c

Lines changed: 62 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -74,14 +74,18 @@ int main(int argc, char *argv[]) {
7474
int ret = 0;
7575
FILE *fd;
7676

77-
/* AND: Several filepaths are hardcoded here, these must be made
78-
configurable */
79-
/* AND: P4A uses env vars...not sure what's best */
80-
LOGP("Initialize Python for Android");
77+
setenv("P4A_BOOTSTRAP", "WEBVIEW", 1); // env var to identify p4a to applications
78+
79+
LOGP("Initializing Python for Android");
8180
env_argument = getenv("ANDROID_ARGUMENT");
8281
setenv("ANDROID_APP_PATH", env_argument, 1);
8382
env_entrypoint = getenv("ANDROID_ENTRYPOINT");
8483
env_logname = getenv("PYTHON_NAME");
84+
85+
if (!getenv("ANDROID_UNPACK")) {
86+
/* ANDROID_UNPACK currently isn't set in services */
87+
setenv("ANDROID_UNPACK", env_argument, 1);
88+
}
8589

8690
if (env_logname == NULL) {
8791
env_logname = "python";
@@ -102,34 +106,52 @@ int main(int argc, char *argv[]) {
102106

103107
LOGP("Preparing to initialize python");
104108

105-
if (dir_exists("crystax_python/")) {
106-
LOGP("crystax_python exists");
107-
char paths[256];
108-
snprintf(paths, 256,
109-
"%s/crystax_python/stdlib.zip:%s/crystax_python/modules",
110-
env_argument, env_argument);
111-
/* snprintf(paths, 256, "%s/stdlib.zip:%s/modules", env_argument,
112-
* env_argument); */
109+
// Set up the python path
110+
char paths[256];
111+
112+
char crystax_python_dir[256];
113+
snprintf(crystax_python_dir, 256,
114+
"%s/crystax_python", getenv("ANDROID_UNPACK"));
115+
char python_bundle_dir[256];
116+
snprintf(python_bundle_dir, 256,
117+
"%s/_python_bundle", getenv("ANDROID_UNPACK"));
118+
if (dir_exists(crystax_python_dir) || dir_exists(python_bundle_dir)) {
119+
if (dir_exists(crystax_python_dir)) {
120+
LOGP("crystax_python exists");
121+
snprintf(paths, 256,
122+
"%s/stdlib.zip:%s/modules",
123+
crystax_python_dir, crystax_python_dir);
124+
}
125+
126+
if (dir_exists(python_bundle_dir)) {
127+
LOGP("_python_bundle dir exists");
128+
snprintf(paths, 256,
129+
"%s/stdlib.zip:%s/modules",
130+
python_bundle_dir, python_bundle_dir);
131+
}
132+
113133
LOGP("calculated paths to be...");
114134
LOGP(paths);
115135

116-
#if PY_MAJOR_VERSION >= 3
117-
wchar_t *wchar_paths = Py_DecodeLocale(paths, NULL);
118-
Py_SetPath(wchar_paths);
119-
#else
120-
char *wchar_paths = paths;
121-
LOGP("Can't Py_SetPath in python2, so crystax python2 doesn't work yet");
122-
exit(1);
123-
#endif
136+
#if PY_MAJOR_VERSION >= 3
137+
wchar_t *wchar_paths = Py_DecodeLocale(paths, NULL);
138+
Py_SetPath(wchar_paths);
139+
#endif
124140

125-
LOGP("set wchar paths...");
141+
LOGP("set wchar paths...");
126142
} else {
127-
LOGP("crystax_python does not exist");
143+
// We do not expect to see crystax_python any more, so no point
144+
// reminding the user about it. If it does exist, we'll have
145+
// logged it earlier.
146+
LOGP("_python_bundle does not exist");
128147
}
129148

130149
Py_Initialize();
131150

132151
#if PY_MAJOR_VERSION < 3
152+
// Can't Py_SetPath in python2 but we can set PySys_SetPath, which must
153+
// be applied after Py_Initialize rather than before like Py_SetPath
154+
PySys_SetPath(paths);
133155
PySys_SetArgv(argc, argv);
134156
#endif
135157

@@ -151,24 +173,25 @@ int main(int argc, char *argv[]) {
151173
* replace sys.path with our path
152174
*/
153175
PyRun_SimpleString("import sys, posix\n");
154-
if (dir_exists("lib")) {
155-
/* If we built our own python, set up the paths correctly */
156-
LOGP("Setting up python from ANDROID_PRIVATE");
157-
PyRun_SimpleString("private = posix.environ['ANDROID_PRIVATE']\n"
158-
"argument = posix.environ['ANDROID_ARGUMENT']\n"
159-
"sys.path[:] = [ \n"
160-
" private + '/lib/python27.zip', \n"
161-
" private + '/lib/python2.7/', \n"
162-
" private + '/lib/python2.7/lib-dynload/', \n"
163-
" private + '/lib/python2.7/site-packages/', \n"
164-
" argument ]\n");
176+
177+
char add_site_packages_dir[256];
178+
if (dir_exists(crystax_python_dir)) {
179+
snprintf(add_site_packages_dir, 256,
180+
"sys.path.append('%s/site-packages')",
181+
crystax_python_dir);
182+
183+
PyRun_SimpleString("import sys\n"
184+
"sys.argv = ['notaninterpreterreally']\n"
185+
"from os.path import realpath, join, dirname");
186+
PyRun_SimpleString(add_site_packages_dir);
187+
/* "sys.path.append(join(dirname(realpath(__file__)), 'site-packages'))") */
188+
PyRun_SimpleString("sys.path = ['.'] + sys.path");
165189
}
166190

167-
if (dir_exists("crystax_python")) {
168-
char add_site_packages_dir[256];
191+
if (dir_exists(python_bundle_dir)) {
169192
snprintf(add_site_packages_dir, 256,
170-
"sys.path.append('%s/crystax_python/site-packages')",
171-
env_argument);
193+
"sys.path.append('%s/site-packages')",
194+
python_bundle_dir);
172195

173196
PyRun_SimpleString("import sys\n"
174197
"sys.argv = ['notaninterpreterreally']\n"
@@ -306,6 +329,7 @@ JNIEXPORT void JNICALL Java_org_kivy_android_PythonService_nativeStart(
306329
setenv("PYTHONHOME", python_home, 1);
307330
setenv("PYTHONPATH", python_path, 1);
308331
setenv("PYTHON_SERVICE_ARGUMENT", arg, 1);
332+
setenv("P4A_BOOTSTRAP", "WEBVIEW", 1);
309333

310334
char *argv[] = {"."};
311335
/* ANDROID_ARGUMENT points to service subdir,
@@ -317,9 +341,6 @@ JNIEXPORT void JNICALL Java_org_kivy_android_PythonService_nativeStart(
317341
void Java_org_kivy_android_PythonActivity_nativeSetEnv(
318342
JNIEnv* env, jclass jcls,
319343
jstring j_name, jstring j_value)
320-
/* JNIEXPORT void JNICALL Java_org_libsdl_app_SDLActivity_nativeSetEnv( */
321-
/* JNIEnv* env, jclass jcls, */
322-
/* jstring j_name, jstring j_value) */
323344
{
324345
jboolean iscopy;
325346
const char *name = (*env)->GetStringUTFChars(env, j_name, &iscopy);
@@ -334,7 +355,7 @@ void Java_org_kivy_android_PythonActivity_nativeInit(JNIEnv* env, jclass cls, jo
334355
{
335356
/* This nativeInit follows SDL2 */
336357

337-
/* This interface could expand with ABI negotiation, calbacks, etc. */
358+
/* This interface could expand with ABI negotiation, callbacks, etc. */
338359
/* SDL_Android_Init(env, cls); */
339360

340361
/* SDL_SetMainReady(); */

pythonforandroid/bootstraps/webview/build/src/main/java/org/kivy/android/PythonActivity.java

Lines changed: 42 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -26,18 +26,21 @@
2626
import android.content.Intent;
2727
import android.util.Log;
2828
import android.widget.Toast;
29+
import android.os.AsyncTask;
2930
import android.os.Bundle;
3031
import android.os.PowerManager;
3132
import android.graphics.PixelFormat;
3233
import android.view.SurfaceHolder;
3334
import android.content.Context;
35+
import android.content.pm.ActivityInfo;
3436
import android.content.pm.PackageManager;
3537
import android.content.pm.ApplicationInfo;
3638
import android.content.Intent;
3739
import android.widget.ImageView;
3840
import java.io.InputStream;
3941
import android.graphics.Bitmap;
4042
import android.graphics.BitmapFactory;
43+
import android.graphics.Color;
4144

4245
import android.widget.AbsoluteLayout;
4346
import android.view.ViewGroup.LayoutParams;
@@ -73,6 +76,11 @@ public class PythonActivity extends Activity {
7376
private Bundle mMetaData = null;
7477
private PowerManager.WakeLock mWakeLock = null;
7578

79+
public String getAppRoot() {
80+
String app_root = getFilesDir().getAbsolutePath() + "/app";
81+
return app_root;
82+
}
83+
7684
public static void initialize() {
7785
// The static nature of the singleton and Android quirkyness force us to initialize everything here
7886
// Otherwise, when exiting the app and returning to it, these variables *keep* their pre exit values
@@ -87,13 +95,20 @@ protected void onCreate(Bundle savedInstanceState) {
8795
resourceManager = new ResourceManager(this);
8896

8997
Log.v(TAG, "Ready to unpack");
90-
unpackData("private", getFilesDir());
98+
File app_root_file = new File(getAppRoot());
99+
unpackData("private", app_root_file);
91100

92-
this.mActivity = this;
101+
Log.v(TAG, "About to do super onCreate");
102+
super.onCreate(savedInstanceState);
103+
Log.v(TAG, "Did super onCreate");
93104

105+
this.mActivity = this;
106+
//this.showLoadingScreen();
94107
Log.v("Python", "Device: " + android.os.Build.DEVICE);
95108
Log.v("Python", "Model: " + android.os.Build.MODEL);
96-
super.onCreate(savedInstanceState);
109+
110+
//Log.v(TAG, "Ready to unpack");
111+
//new UnpackFilesTask().execute(getAppRoot());
97112

98113
PythonActivity.initialize();
99114

@@ -134,10 +149,12 @@ public void onClick(DialogInterface dialog,int id) {
134149
}
135150

136151
// Set up the webview
152+
String app_root_dir = getAppRoot();
153+
137154
mWebView = new WebView(this);
138155
mWebView.getSettings().setJavaScriptEnabled(true);
139156
mWebView.getSettings().setDomStorageEnabled(true);
140-
mWebView.loadUrl("file:///" + mActivity.getFilesDir().getAbsolutePath() + "/_load.html");
157+
mWebView.loadUrl("file:///" + app_root_dir + "/_load.html");
141158

142159
mWebView.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
143160
mWebView.setWebViewClient(new WebViewClient() {
@@ -147,30 +164,32 @@ public boolean shouldOverrideUrlLoading(WebView view, String url) {
147164
return false;
148165
}
149166
});
150-
151167
mLayout = new AbsoluteLayout(this);
152168
mLayout.addView(mWebView);
153169

154170
setContentView(mLayout);
155171

156172
String mFilesDirectory = mActivity.getFilesDir().getAbsolutePath();
173+
157174
Log.v(TAG, "Setting env vars for start.c and Python to use");
158-
PythonActivity.nativeSetEnv("ANDROID_PRIVATE", mFilesDirectory);
159-
PythonActivity.nativeSetEnv("ANDROID_ARGUMENT", mFilesDirectory);
160-
PythonActivity.nativeSetEnv("ANDROID_APP_PATH", mFilesDirectory);
161-
PythonActivity.nativeSetEnv("ANDROID_UNPACK", mFilesDirectory);
162175
PythonActivity.nativeSetEnv("ANDROID_ENTRYPOINT", "main.pyo");
163-
PythonActivity.nativeSetEnv("PYTHONHOME", mFilesDirectory);
164-
PythonActivity.nativeSetEnv("PYTHONPATH", mFilesDirectory + ":" + mFilesDirectory + "/lib");
176+
PythonActivity.nativeSetEnv("ANDROID_ARGUMENT", app_root_dir);
177+
PythonActivity.nativeSetEnv("ANDROID_APP_PATH", app_root_dir);
178+
PythonActivity.nativeSetEnv("ANDROID_PRIVATE", mFilesDirectory);
179+
PythonActivity.nativeSetEnv("ANDROID_UNPACK", app_root_dir);
180+
PythonActivity.nativeSetEnv("PYTHONHOME", app_root_dir);
181+
PythonActivity.nativeSetEnv("PYTHONPATH", app_root_dir + ":" + app_root_dir + "/lib");
182+
PythonActivity.nativeSetEnv("PYTHONOPTIMIZE", "2");
165183

166184
try {
167185
Log.v(TAG, "Access to our meta-data...");
168-
this.mMetaData = this.mActivity.getPackageManager().getApplicationInfo(
169-
this.mActivity.getPackageName(), PackageManager.GET_META_DATA).metaData;
186+
mActivity.mMetaData = mActivity.getPackageManager().getApplicationInfo(
187+
mActivity.getPackageName(), PackageManager.GET_META_DATA).metaData;
170188

171-
PowerManager pm = (PowerManager) this.mActivity.getSystemService(Context.POWER_SERVICE);
172-
if ( this.mMetaData.getInt("wakelock") == 1 ) {
173-
this.mWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "Screen On");
189+
PowerManager pm = (PowerManager) mActivity.getSystemService(Context.POWER_SERVICE);
190+
if ( mActivity.mMetaData.getInt("wakelock") == 1 ) {
191+
mActivity.mWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "Screen On");
192+
mActivity.mWakeLock.acquire();
174193
}
175194
} catch (PackageManager.NameNotFoundException e) {
176195
}
@@ -181,19 +200,13 @@ public boolean shouldOverrideUrlLoading(WebView view, String url) {
181200

182201
final Thread wvThread = new Thread(new WebViewLoaderMain(), "WvThread");
183202
wvThread.start();
184-
}
185203

186-
@Override
187-
public void onDestroy() {
188-
Log.i("Destroy", "end of app");
189-
super.onDestroy();
190-
191-
// make sure all child threads (python_thread) are stopped
192-
android.os.Process.killProcess(android.os.Process.myPid());
193204
}
194205

195206
public void loadLibraries() {
196-
PythonUtil.loadLibraries(getFilesDir());
207+
String app_root = new String(getAppRoot());
208+
File app_root_file = new File(app_root);
209+
PythonUtil.loadLibraries(app_root_file);
197210
}
198211

199212
public void recursiveDelete(File f) {
@@ -402,12 +415,13 @@ public static void start_service(String serviceTitle, String serviceDescription,
402415
Intent serviceIntent = new Intent(PythonActivity.mActivity, PythonService.class);
403416
String argument = PythonActivity.mActivity.getFilesDir().getAbsolutePath();
404417
String filesDirectory = argument;
418+
String app_root_dir = PythonActivity.mActivity.getAppRoot();
405419
serviceIntent.putExtra("androidPrivate", argument);
406-
serviceIntent.putExtra("androidArgument", argument);
420+
serviceIntent.putExtra("androidArgument", app_root_dir);
407421
serviceIntent.putExtra("serviceEntrypoint", "service/main.pyo");
408422
serviceIntent.putExtra("pythonName", "python");
409-
serviceIntent.putExtra("pythonHome", argument);
410-
serviceIntent.putExtra("pythonPath", argument + ":" + filesDirectory + "/lib");
423+
serviceIntent.putExtra("pythonHome", app_root_dir);
424+
serviceIntent.putExtra("pythonPath", app_root_dir + ":" + app_root_dir + "/lib");
411425
serviceIntent.putExtra("serviceTitle", serviceTitle);
412426
serviceIntent.putExtra("serviceDescription", serviceDescription);
413427
serviceIntent.putExtra("pythonServiceArgument", pythonServiceArgument);

pythonforandroid/bootstraps/webview/build/src/main/java/org/kivy/android/PythonService.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import android.app.Notification;
1313
import android.app.PendingIntent;
1414
import android.os.Process;
15+
import java.io.File;
1516

1617
import org.kivy.android.PythonUtil;
1718

@@ -131,7 +132,9 @@ public void onDestroy() {
131132

132133
@Override
133134
public void run(){
134-
PythonUtil.loadLibraries(getFilesDir());
135+
String app_root = getFilesDir().getAbsolutePath() + "/app";
136+
File app_root_file = new File(app_root);
137+
PythonUtil.loadLibraries(app_root_file);
135138
this.mService = this;
136139
nativeStart(
137140
androidPrivate, androidArgument,

0 commit comments

Comments
 (0)