Skip to content

Commit 331b6b6

Browse files
committed
Added pyjnius code for webview bootstrap
1 parent 91fee21 commit 331b6b6

File tree

3 files changed

+171
-1
lines changed

3 files changed

+171
-1
lines changed

pythonforandroid/bootstraps/webview/build/jni/src/Android.mk

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ LOCAL_MODULE := main
77
# LOCAL_C_INCLUDES := $(LOCAL_PATH)/$(SDL_PATH)/include
88

99
# Add your application source files here...
10-
LOCAL_SRC_FILES := start.c
10+
LOCAL_SRC_FILES := start.c pyjniusjni.c
1111

1212
LOCAL_CFLAGS += -I$(LOCAL_PATH)/../../../../other_builds/$(PYTHON2_NAME)/$(ARCH)/python2/python-install/include/python2.7 $(EXTRA_CFLAGS)
1313

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
2+
#include <pthread.h>
3+
#include <jni.h>
4+
5+
#define LOGI(...) do {} while (0)
6+
#define LOGE(...) do {} while (0)
7+
8+
#include "android/log.h"
9+
10+
/* These JNI management functions are taken from SDL2 */
11+
12+
/* #define LOG(n, x) __android_log_write(ANDROID_LOG_INFO, (n), (x)) */
13+
/* #define LOGP(x) LOG("python", (x)) */
14+
#define LOG_TAG "Python_android"
15+
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
16+
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
17+
18+
19+
/* Function headers */
20+
JNIEnv* Android_JNI_GetEnv(void);
21+
static void Android_JNI_ThreadDestroyed(void*);
22+
23+
static pthread_key_t mThreadKey;
24+
static JavaVM* mJavaVM;
25+
26+
int Android_JNI_SetupThread(void)
27+
{
28+
Android_JNI_GetEnv();
29+
return 1;
30+
}
31+
32+
/* Library init */
33+
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)
34+
{
35+
JNIEnv *env;
36+
mJavaVM = vm;
37+
LOGI("JNI_OnLoad called");
38+
if ((*mJavaVM)->GetEnv(mJavaVM, (void**) &env, JNI_VERSION_1_4) != JNI_OK) {
39+
LOGE("Failed to get the environment using GetEnv()");
40+
return -1;
41+
}
42+
/*
43+
* Create mThreadKey so we can keep track of the JNIEnv assigned to each thread
44+
* Refer to http://developer.android.com/guide/practices/design/jni.html for the rationale behind this
45+
*/
46+
if (pthread_key_create(&mThreadKey, Android_JNI_ThreadDestroyed) != 0) {
47+
48+
__android_log_print(ANDROID_LOG_ERROR, "SDL", "Error initializing pthread key");
49+
}
50+
Android_JNI_SetupThread();
51+
52+
return JNI_VERSION_1_4;
53+
}
54+
55+
JNIEnv* Android_JNI_GetEnv(void)
56+
{
57+
/* From http://developer.android.com/guide/practices/jni.html
58+
* All threads are Linux threads, scheduled by the kernel.
59+
* They're usually started from managed code (using Thread.start), but they can also be created elsewhere and then
60+
* attached to the JavaVM. For example, a thread started with pthread_create can be attached with the
61+
* JNI AttachCurrentThread or AttachCurrentThreadAsDaemon functions. Until a thread is attached, it has no JNIEnv,
62+
* and cannot make JNI calls.
63+
* Attaching a natively-created thread causes a java.lang.Thread object to be constructed and added to the "main"
64+
* ThreadGroup, making it visible to the debugger. Calling AttachCurrentThread on an already-attached thread
65+
* is a no-op.
66+
* Note: You can call this function any number of times for the same thread, there's no harm in it
67+
*/
68+
69+
JNIEnv *env;
70+
int status = (*mJavaVM)->AttachCurrentThread(mJavaVM, &env, NULL);
71+
if(status < 0) {
72+
LOGE("failed to attach current thread");
73+
return 0;
74+
}
75+
76+
/* From http://developer.android.com/guide/practices/jni.html
77+
* Threads attached through JNI must call DetachCurrentThread before they exit. If coding this directly is awkward,
78+
* in Android 2.0 (Eclair) and higher you can use pthread_key_create to define a destructor function that will be
79+
* called before the thread exits, and call DetachCurrentThread from there. (Use that key with pthread_setspecific
80+
* to store the JNIEnv in thread-local-storage; that way it'll be passed into your destructor as the argument.)
81+
* Note: The destructor is not called unless the stored value is != NULL
82+
* Note: You can call this function any number of times for the same thread, there's no harm in it
83+
* (except for some lost CPU cycles)
84+
*/
85+
pthread_setspecific(mThreadKey, (void*) env);
86+
87+
return env;
88+
}
89+
90+
static void Android_JNI_ThreadDestroyed(void* value)
91+
{
92+
/* The thread is being destroyed, detach it from the Java VM and set the mThreadKey value to NULL as required */
93+
JNIEnv *env = (JNIEnv*) value;
94+
if (env != NULL) {
95+
(*mJavaVM)->DetachCurrentThread(mJavaVM);
96+
pthread_setspecific(mThreadKey, NULL);
97+
}
98+
}
99+
100+
void *SDL_AndroidGetJNIEnv()
101+
{
102+
return Android_JNI_GetEnv();
103+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package org.kivy.android;
2+
3+
import android.util.Log;
4+
5+
import java.io.IOException;
6+
import java.net.Socket;
7+
import java.net.InetSocketAddress;
8+
9+
import android.os.SystemClock;
10+
11+
import android.os.Handler;
12+
13+
import org.kivy.android.PythonActivity;
14+
15+
public class WebViewLoader {
16+
private static final String TAG = "WebViewLoader";
17+
18+
public static void testConnection() {
19+
20+
while (true) {
21+
if (WebViewLoader.pingHost("localhost", 5000, 100)) {
22+
Log.v(TAG, "successfully pinged localhost");
23+
// PythonActivity.mWebView.loadUrl("http://localhost:5000");
24+
// PythonActivity.mWebView.loadUrl("http://www.google.com");
25+
26+
Handler mainHandler = new Handler(PythonActivity.mActivity.getMainLooper());
27+
28+
Runnable myRunnable = new Runnable() {
29+
@Override
30+
public void run() {
31+
// PythonActivity.mActivity.mWebView.loadUrl("http://127.0.0.1:5000/");
32+
// PythonActivity.mActivity.mWebView.loadUrl("http://www.google.com");
33+
PythonActivity.mActivity.mWebView.loadUrl("file:///" + PythonActivity.mActivity.getFilesDir().getAbsolutePath() + "/load_immediate.html");
34+
// PythonActivity.mActivity.mWebView.loadUrl("file:///" + PythonActivity.mActivity.getFilesDir().getAbsolutePath() + "/_load2.html");
35+
Log.v(TAG, "did webview load!");
36+
}
37+
// public void run() {PythonActivity.mActivity.mWebView.loadUrl("http://127.0.0.1:5000");}
38+
};
39+
mainHandler.post(myRunnable);
40+
break;
41+
42+
} else {
43+
Log.v(TAG, "could not ping localhost");
44+
try {
45+
Thread.sleep(100);
46+
} catch(InterruptedException e) {
47+
Log.v(TAG, "InterruptedException occurred when sleeping");
48+
}
49+
}
50+
}
51+
52+
Log.v(TAG, "testConnection finished");
53+
54+
}
55+
56+
public static boolean pingHost(String host, int port, int timeout) {
57+
Socket socket = new Socket();
58+
try {
59+
socket.connect(new InetSocketAddress(host, port), timeout);
60+
return true;
61+
} catch (IOException e) {
62+
return false; // Either timeout or unreachable or failed DNS lookup.
63+
}
64+
}
65+
}
66+
67+

0 commit comments

Comments
 (0)