Skip to content

Commit 42e05d1

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 caf9f4b commit 42e05d1

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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy