Skip to content

Commit 36bc8a4

Browse files
authored
Merge pull request #2092 from zworkb/android-library
Android library
2 parents ca9c467 + 15590da commit 36bc8a4

File tree

19 files changed

+505
-189
lines changed

19 files changed

+505
-189
lines changed

pythonforandroid/bdistapk.py

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,16 @@ def argv_contains(t):
1414
return False
1515

1616

17-
class BdistAPK(Command):
18-
description = 'Create an APK with python-for-android'
17+
class Bdist(Command):
1918

2019
user_options = []
20+
package_type = None
2121

2222
def initialize_options(self):
2323
for option in self.user_options:
2424
setattr(self, option[0].strip('=').replace('-', '_'), None)
2525

26-
option_dict = self.distribution.get_option_dict('apk')
26+
option_dict = self.distribution.get_option_dict(self.package_type)
2727

2828
# This is a hack, we probably aren't supposed to loop through
2929
# the option_dict so early because distutils does exactly the
@@ -34,7 +34,7 @@ def initialize_options(self):
3434

3535
def finalize_options(self):
3636

37-
setup_options = self.distribution.get_option_dict('apk')
37+
setup_options = self.distribution.get_option_dict(self.package_type)
3838
for (option, (source, value)) in setup_options.items():
3939
if source == 'command line':
4040
continue
@@ -75,7 +75,7 @@ def run(self):
7575
self.prepare_build_dir()
7676

7777
from pythonforandroid.entrypoints import main
78-
sys.argv[1] = 'apk'
78+
sys.argv[1] = self.package_type
7979
main()
8080

8181
def prepare_build_dir(self):
@@ -127,6 +127,22 @@ def prepare_build_dir(self):
127127
)
128128

129129

130+
class BdistAPK(Bdist):
131+
"""
132+
distutil command handler for 'apk'
133+
"""
134+
description = 'Create an APK with python-for-android'
135+
package_type = 'apk'
136+
137+
138+
class BdistAAR(Bdist):
139+
"""
140+
distutil command handler for 'aar'
141+
"""
142+
description = 'Create an AAR with python-for-android'
143+
package_type = 'aar'
144+
145+
130146
def _set_user_options():
131147
# This seems like a silly way to do things, but not sure if there's a
132148
# better way to pass arbitrary options onwards to p4a

pythonforandroid/bootstrap.py

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from pythonforandroid.recipe import Recipe
1515

1616

17-
def copy_files(src_root, dest_root, override=True):
17+
def copy_files(src_root, dest_root, override=True, symlink=False):
1818
for root, dirnames, filenames in walk(src_root):
1919
for filename in filenames:
2020
subdir = normpath(root.replace(src_root, ""))
@@ -29,7 +29,10 @@ def copy_files(src_root, dest_root, override=True):
2929
if override and os.path.exists(dest_file):
3030
os.unlink(dest_file)
3131
if not os.path.exists(dest_file):
32-
shutil.copy(src_file, dest_file)
32+
if symlink:
33+
os.symlink(src_file, dest_file)
34+
else:
35+
shutil.copy(src_file, dest_file)
3336
else:
3437
os.makedirs(dest_file)
3538

@@ -109,7 +112,7 @@ def check_recipe_choices(self):
109112
and optional dependencies are being used,
110113
and returns a list of these.'''
111114
recipes = []
112-
built_recipes = self.ctx.recipe_build_order
115+
built_recipes = self.ctx.recipe_build_order or []
113116
for recipe in self.recipe_depends:
114117
if isinstance(recipe, (tuple, list)):
115118
for alternative in recipe:
@@ -137,21 +140,27 @@ def name(self):
137140
modname = self.__class__.__module__
138141
return modname.split(".", 2)[-1]
139142

143+
def get_bootstrap_dirs(self):
144+
"""get all bootstrap directories, following the MRO path"""
145+
146+
# get all bootstrap names along the __mro__, cutting off Bootstrap and object
147+
classes = self.__class__.__mro__[:-2]
148+
bootstrap_names = [cls.name for cls in classes] + ['common']
149+
bootstrap_dirs = [
150+
join(self.ctx.root_dir, 'bootstraps', bootstrap_name)
151+
for bootstrap_name in reversed(bootstrap_names)
152+
]
153+
return bootstrap_dirs
154+
140155
def prepare_build_dir(self):
141-
'''Ensure that a build dir exists for the recipe. This same single
142-
dir will be used for building all different archs.'''
156+
"""Ensure that a build dir exists for the recipe. This same single
157+
dir will be used for building all different archs."""
158+
bootstrap_dirs = self.get_bootstrap_dirs()
159+
# now do a cumulative copy of all bootstrap dirs
143160
self.build_dir = self.get_build_dir()
144-
self.common_dir = self.get_common_dir()
145-
copy_files(join(self.bootstrap_dir, 'build'), self.build_dir)
146-
copy_files(join(self.common_dir, 'build'), self.build_dir,
147-
override=False)
148-
if self.ctx.symlink_java_src:
149-
info('Symlinking java src instead of copying')
150-
shprint(sh.rm, '-r', join(self.build_dir, 'src'))
151-
shprint(sh.mkdir, join(self.build_dir, 'src'))
152-
for dirn in listdir(join(self.bootstrap_dir, 'build', 'src')):
153-
shprint(sh.ln, '-s', join(self.bootstrap_dir, 'build', 'src', dirn),
154-
join(self.build_dir, 'src'))
161+
for bootstrap_dir in bootstrap_dirs:
162+
copy_files(join(bootstrap_dir, 'build'), self.build_dir, symlink=self.ctx.symlink_bootstrap_files)
163+
155164
with current_directory(self.build_dir):
156165
with open('project.properties', 'w') as fileh:
157166
fileh.write('target=android-{}'.format(self.ctx.android_api))

pythonforandroid/bootstraps/common/build/build.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ def compile_dir(dfn, optimize_python=True):
225225
def make_package(args):
226226
# If no launcher is specified, require a main.py/main.pyo:
227227
if (get_bootstrap_name() != "sdl" or args.launcher is None) and \
228-
get_bootstrap_name() != "webview":
228+
get_bootstrap_name() not in ["webview", "service_library"]:
229229
# (webview doesn't need an entrypoint, apparently)
230230
if args.private is None or (
231231
not exists(join(realpath(args.private), 'main.py')) and
@@ -479,6 +479,7 @@ def make_package(args):
479479
android_api=android_api,
480480
build_tools_version=build_tools_version,
481481
debug_build="debug" in args.build_mode,
482+
is_library=(get_bootstrap_name() == 'service_library'),
482483
)
483484

484485
# ant build templates

pythonforandroid/bootstraps/common/build/src/main/java/org/kivy/android/PythonUtil.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ protected static ArrayList<String> getLibraries(File libsDir) {
3939
libsList.add("python3.5m");
4040
libsList.add("python3.6m");
4141
libsList.add("python3.7m");
42+
libsList.add("python3.8m");
4243
libsList.add("main");
4344
return libsList;
4445
}
@@ -59,7 +60,7 @@ public static void loadLibraries(File filesDir, File libsDir) {
5960
// load, and it has failed, give a more
6061
// general error
6162
Log.v(TAG, "Library loading error: " + e.getMessage());
62-
if (lib.startsWith("python3.7") && !foundPython) {
63+
if (lib.startsWith("python3.8") && !foundPython) {
6364
throw new java.lang.RuntimeException("Could not load any libpythonXXX.so");
6465
} else if (lib.startsWith("python")) {
6566
continue;

pythonforandroid/bootstraps/common/build/templates/build.tmpl.gradle

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,11 @@ allprojects {
2222
}
2323
}
2424

25+
{% if is_library %}
26+
apply plugin: 'com.android.library'
27+
{% else %}
2528
apply plugin: 'com.android.application'
29+
{% endif %}
2630

2731
android {
2832
compileSdkVersion {{ android_api }}
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>

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