Skip to content

Commit 0b81c78

Browse files
committed
p4a support for creating aar libraries
* ported @xuhcc's PR 1063 to recent p4a master * bootstraps dirs are cumulatively copied based on their inheritance, can be arbitrarily deep * add symlink param to copy_files, when set the copy target are symlinked * support for the aar directive in buildozer * create a 'p4a aar' command, so that lots of cluttering conditionals can be moved away from toolchain.apk() * began to remove ant support (@inclement allowed me to do so) * renamed library bootstrap to service_library, because that describe it better * test setup setup_testlib_service.py * renamed symlink_java_src to symlink_bootstrap_files * None is not allowed as bootstrap parameter * switched tests to use the sdl2 bootstrap
1 parent 47c9c33 commit 0b81c78

File tree

9 files changed

+440
-143
lines changed

9 files changed

+440
-143
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from pythonforandroid.bootstraps.service_only import ServiceOnlyBootstrap
2+
3+
4+
class ServiceLibraryBootstrap(ServiceOnlyBootstrap):
5+
6+
name = 'service_library'
7+
8+
9+
bootstrap = ServiceLibraryBootstrap()
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
2+
#define BOOTSTRAP_NAME_LIBRARY
3+
#define BOOTSTRAP_USES_NO_SDL_HEADERS
4+
5+
const char bootstrap_name[] = "service_library";
6+
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package org.kivy.android;
2+
3+
import android.app.Activity;
4+
5+
// Required by PythonService class
6+
public class PythonActivity extends Activity {
7+
8+
}
9+
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
// This string is autogenerated by ChangeAppSettings.sh, do not change
2+
// spaces amount
3+
package org.renpy.android;
4+
5+
import java.io.*;
6+
7+
import android.content.Context;
8+
import android.util.Log;
9+
10+
import java.io.BufferedInputStream;
11+
import java.io.BufferedOutputStream;
12+
import java.io.IOException;
13+
import java.io.InputStream;
14+
import java.io.FileInputStream;
15+
import java.io.FileOutputStream;
16+
import java.io.File;
17+
18+
import java.util.zip.GZIPInputStream;
19+
20+
import android.content.res.AssetManager;
21+
22+
import org.kamranzafar.jtar.*;
23+
24+
public class AssetExtract {
25+
26+
private AssetManager mAssetManager = null;
27+
private Context ctx = null;
28+
29+
public AssetExtract(Context context) {
30+
ctx = context;
31+
mAssetManager = ctx.getAssets();
32+
}
33+
34+
public boolean extractTar(String asset, String target) {
35+
36+
byte buf[] = new byte[1024 * 1024];
37+
38+
InputStream assetStream = null;
39+
TarInputStream tis = null;
40+
41+
try {
42+
assetStream = mAssetManager.open(asset, AssetManager.ACCESS_STREAMING);
43+
tis = new TarInputStream(new BufferedInputStream(new GZIPInputStream(new BufferedInputStream(assetStream, 8192)), 8192));
44+
} catch (IOException e) {
45+
Log.e("python", "opening up extract tar", e);
46+
return false;
47+
}
48+
49+
while (true) {
50+
TarEntry entry = null;
51+
52+
try {
53+
entry = tis.getNextEntry();
54+
} catch ( java.io.IOException e ) {
55+
Log.e("python", "extracting tar", e);
56+
return false;
57+
}
58+
59+
if ( entry == null ) {
60+
break;
61+
}
62+
63+
Log.v("python", "extracting " + entry.getName());
64+
65+
if (entry.isDirectory()) {
66+
67+
try {
68+
new File(target +"/" + entry.getName()).mkdirs();
69+
} catch ( SecurityException e ) { };
70+
71+
continue;
72+
}
73+
74+
OutputStream out = null;
75+
String path = target + "/" + entry.getName();
76+
77+
try {
78+
out = new BufferedOutputStream(new FileOutputStream(path), 8192);
79+
} catch ( FileNotFoundException e ) {
80+
} catch ( SecurityException e ) { };
81+
82+
if ( out == null ) {
83+
Log.e("python", "could not open " + path);
84+
return false;
85+
}
86+
87+
try {
88+
while (true) {
89+
int len = tis.read(buf);
90+
91+
if (len == -1) {
92+
break;
93+
}
94+
95+
out.write(buf, 0, len);
96+
}
97+
98+
out.flush();
99+
out.close();
100+
} catch ( java.io.IOException e ) {
101+
Log.e("python", "extracting zip", e);
102+
return false;
103+
}
104+
}
105+
106+
try {
107+
tis.close();
108+
assetStream.close();
109+
} catch (IOException e) {
110+
// pass
111+
}
112+
113+
return true;
114+
}
115+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3+
package="{{ args.package }}"
4+
android:versionCode="{{ args.numeric_version }}"
5+
android:versionName="{{ args.version }}">
6+
7+
<!-- Android 2.3.3 -->
8+
<uses-sdk android:minSdkVersion="{{ args.min_sdk_version }}" android:targetSdkVersion="{{ android_api }}" />
9+
10+
<application>
11+
{% for name in service_names %}
12+
<service android:name="{{ args.package }}.Service{{ name|capitalize }}"
13+
android:process=":service_{{ name }}"
14+
android:exported="true" />
15+
{% endfor %}
16+
</application>
17+
18+
</manifest>
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
package {{ args.package }};
2+
3+
import java.io.File;
4+
import java.io.FileInputStream;
5+
import java.io.FileOutputStream;
6+
import java.io.InputStream;
7+
8+
import android.os.Build;
9+
import android.content.Intent;
10+
import android.content.Context;
11+
import android.content.res.Resources;
12+
import android.util.Log;
13+
14+
import org.renpy.android.AssetExtract;
15+
import org.kivy.android.PythonService;
16+
17+
public class Service{{ name|capitalize }} extends PythonService {
18+
19+
private static final String TAG = "PythonService";
20+
21+
public static void prepare(Context ctx) {
22+
String appRoot = getAppRoot(ctx);
23+
Log.v(TAG, "Ready to unpack");
24+
File app_root_file = new File(appRoot);
25+
unpackData(ctx, "private", app_root_file);
26+
}
27+
28+
public static void start(Context ctx, String pythonServiceArgument) {
29+
String appRoot = getAppRoot(ctx);
30+
Intent intent = new Intent(ctx, Service{{ name|capitalize }}.class);
31+
intent.putExtra("androidPrivate", appRoot);
32+
intent.putExtra("androidArgument", appRoot);
33+
intent.putExtra("serviceEntrypoint", "{{ entrypoint }}");
34+
intent.putExtra("serviceTitle", "{{ name|capitalize }}");
35+
intent.putExtra("serviceDescription", "");
36+
intent.putExtra("pythonName", "{{ name }}");
37+
intent.putExtra("serviceStartAsForeground", "{{ foreground|lower }}");
38+
intent.putExtra("pythonHome", appRoot);
39+
intent.putExtra("androidUnpack", appRoot);
40+
intent.putExtra("pythonPath", appRoot + ":" + appRoot + "/lib");
41+
intent.putExtra("pythonServiceArgument", pythonServiceArgument);
42+
43+
//foreground: {{foreground}}
44+
{% if foreground %}
45+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
46+
ctx.startForegroundService(intent);
47+
} else {
48+
ctx.startService(intent);
49+
}
50+
{% else %}
51+
ctx.startService(intent);
52+
{% endif %}
53+
}
54+
55+
public static String getAppRoot(Context ctx) {
56+
String app_root = ctx.getFilesDir().getAbsolutePath() + "/app";
57+
return app_root;
58+
}
59+
60+
public static String getResourceString(Context ctx, String name) {
61+
// Taken from org.renpy.android.ResourceManager
62+
Resources res = ctx.getResources();
63+
int id = res.getIdentifier(name, "string", ctx.getPackageName());
64+
return res.getString(id);
65+
}
66+
67+
public static void unpackData(Context ctx, final String resource, File target) {
68+
// Taken from PythonActivity class
69+
70+
Log.v(TAG, "UNPACKING!!! " + resource + " " + target.getName());
71+
72+
// The version of data in memory and on disk.
73+
String data_version = getResourceString(ctx, resource + "_version");
74+
String disk_version = null;
75+
76+
Log.v(TAG, "Data version is " + data_version);
77+
78+
// If no version, no unpacking is necessary.
79+
if (data_version == null) {
80+
return;
81+
}
82+
83+
// Check the current disk version, if any.
84+
String filesDir = target.getAbsolutePath();
85+
String disk_version_fn = filesDir + "/" + resource + ".version";
86+
87+
try {
88+
byte buf[] = new byte[64];
89+
InputStream is = new FileInputStream(disk_version_fn);
90+
int len = is.read(buf);
91+
disk_version = new String(buf, 0, len);
92+
is.close();
93+
} catch (Exception e) {
94+
disk_version = "";
95+
}
96+
97+
// If the disk data is out of date, extract it and write the
98+
// version file.
99+
// if (! data_version.equals(disk_version)) {
100+
if (! data_version.equals(disk_version)) {
101+
Log.v(TAG, "Extracting " + resource + " assets.");
102+
103+
// Don't delete existing files
104+
// recursiveDelete(target);
105+
target.mkdirs();
106+
107+
AssetExtract ae = new AssetExtract(ctx);
108+
if (!ae.extractTar(resource + ".mp3", target.getAbsolutePath())) {
109+
Log.v(TAG, "Could not extract " + resource + " data.");
110+
}
111+
112+
try {
113+
// Write .nomedia.
114+
new File(target, ".nomedia").createNewFile();
115+
116+
// Write version file.
117+
FileOutputStream os = new FileOutputStream(disk_version_fn);
118+
os.write(data_version.getBytes());
119+
os.close();
120+
} catch (Exception e) {
121+
Log.w("python", e);
122+
}
123+
}
124+
}
125+
126+
}

pythonforandroid/recipes/android/__init__.py

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,8 @@ def prebuild_arch(self, arch):
3434
if isinstance(ctx_bootstrap, bytes):
3535
ctx_bootstrap = ctx_bootstrap.decode('utf-8')
3636
bootstrap = bootstrap_name = ctx_bootstrap
37-
38-
is_sdl2 = bootstrap_name in ('sdl2', 'sdl2python3', 'sdl2_gradle')
39-
is_webview = bootstrap_name == 'webview'
40-
is_service_only = bootstrap_name == 'service_only'
41-
42-
if is_sdl2 or is_webview or is_service_only:
43-
if is_sdl2:
44-
bootstrap = 'sdl2'
37+
is_sdl2 = (bootstrap_name == "sdl2")
38+
if bootstrap_name in ["sdl2", "webview", "service_only", "service_library"]:
4539
java_ns = u'org.kivy.android'
4640
jni_ns = u'org/kivy/android'
4741
else:

0 commit comments

Comments
 (0)