Skip to content

Commit a169f0d

Browse files
authored
Fixing service_library bootstrap + .aar build. (#2612)
* fix Android 12 operation * fix service_only aar target * flake8 fix * add github actions for aar * fix aar test * fix aar test * fix aar test * fix aar test * group apk and aar logic together * support multi-arch aar build
1 parent 6fa6dde commit a169f0d

File tree

10 files changed

+148
-27
lines changed

10 files changed

+148
-27
lines changed

.github/workflows/push.yml

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ on: ['push', 'pull_request']
55
env:
66
APK_ARTIFACT_FILENAME: bdist_unit_tests_app-debug-1.1-.apk
77
AAB_ARTIFACT_FILENAME: bdist_unit_tests_app-release-1.1-.aab
8+
AAR_ARTIFACT_FILENAME: bdist_unit_tests_app-release-1.1-.aar
89
PYTHONFORANDROID_PREREQUISITES_INSTALL_INTERACTIVE: 0
910

1011
jobs:
@@ -186,6 +187,47 @@ jobs:
186187
name: ${{ matrix.runs_on }}-${{ matrix.bootstrap.name}}-${{ env.AAB_ARTIFACT_FILENAME }}
187188
path: aabs/${{ matrix.runs_on }}-${{ matrix.bootstrap.name}}-${{ env.AAB_ARTIFACT_FILENAME }}
188189

190+
191+
ubuntu_build_aar:
192+
name: Unit test aar [ ${{ matrix.runs_on }} ]
193+
needs: [flake8]
194+
runs-on: ${{ matrix.runs_on }}
195+
continue-on-error: true
196+
strategy:
197+
matrix:
198+
runs_on: [ubuntu-latest]
199+
bootstrap:
200+
- name: service_library
201+
target: testapps-service_library-aar
202+
steps:
203+
- name: Checkout python-for-android
204+
uses: actions/checkout@v2
205+
# helps with GitHub runner getting out of space
206+
- name: Free disk space
207+
run: |
208+
df -h
209+
sudo swapoff -a
210+
sudo rm -f /swapfile
211+
sudo apt -y clean
212+
docker rmi $(docker image ls -aq)
213+
df -h
214+
- name: Pull docker image
215+
run: |
216+
make docker/pull
217+
- name: Build Android AAR Python 3 (arm64-v8a)
218+
run: |
219+
mkdir -p aars
220+
make docker/run/make/with-artifact/aar/${{ matrix.bootstrap.target }}
221+
- name: Rename artifact to include the build platform name
222+
run: |
223+
mv aars/${{ env.AAR_ARTIFACT_FILENAME }} aars/${{ matrix.runs_on }}-${{ matrix.bootstrap.name}}-${{ env.AAR_ARTIFACT_FILENAME }}
224+
- name: Upload aar artifact
225+
uses: actions/upload-artifact@v1
226+
with:
227+
name: ${{ matrix.runs_on }}-${{ matrix.bootstrap.name}}-${{ env.AAR_ARTIFACT_FILENAME }}
228+
path: aars/${{ matrix.runs_on }}-${{ matrix.bootstrap.name}}-${{ env.AAR_ARTIFACT_FILENAME }}
229+
230+
189231
macos_build_aab:
190232
name: Unit test aab [ ${{ matrix.runs_on }} | ${{ matrix.bootstrap.name }} ]
191233
needs: [flake8]

Makefile

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,13 @@ testapps-with-numpy-aab: virtualenv
5555
--requirements libffi,sdl2,pyjnius,kivy,python3,openssl,requests,urllib3,chardet,idna,sqlite3,setuptools,numpy \
5656
--arch=armeabi-v7a --arch=arm64-v8a --arch=x86_64 --arch=x86 --release
5757

58+
testapps-service_library-aar: virtualenv
59+
. $(ACTIVATE) && cd testapps/on_device_unit_tests/ && \
60+
python setup.py aar --sdk-dir $(ANDROID_SDK_HOME) --ndk-dir $(ANDROID_NDK_HOME) \
61+
--bootstrap service_library \
62+
--requirements python3 \
63+
--arch=arm64-v8a --arch=x86 --release
64+
5865
testapps-webview: virtualenv
5966
. $(ACTIVATE) && cd testapps/on_device_unit_tests/ && \
6067
python setup.py apk --sdk-dir $(ANDROID_SDK_HOME) --ndk-dir $(ANDROID_NDK_HOME) \
@@ -102,6 +109,11 @@ docker/run/make/with-artifact/apk/%: docker/build
102109
docker cp p4a-latest:/home/user/app/testapps/on_device_unit_tests/bdist_unit_tests_app-debug-1.1-.apk ./apks
103110
docker rm -fv p4a-latest
104111

112+
docker/run/make/with-artifact/aar/%: docker/build
113+
docker run --name p4a-latest --env-file=.env $(DOCKER_IMAGE) make $*
114+
docker cp p4a-latest:/home/user/app/testapps/on_device_unit_tests/bdist_unit_tests_app-release-1.1-.aar ./aars
115+
docker rm -fv p4a-latest
116+
105117
docker/run/make/with-artifact/aab/%: docker/build
106118
docker run --name p4a-latest --env-file=.env $(DOCKER_IMAGE) make $*
107119
docker cp p4a-latest:/home/user/app/testapps/on_device_unit_tests/bdist_unit_tests_app-release-1.1-.aab ./aabs

pythonforandroid/bdistapk.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ def _set_user_options():
159159

160160
BdistAPK.user_options = user_options
161161
BdistAAB.user_options = user_options
162+
BdistAAR.user_options = user_options
162163

163164

164165
_set_user_options()

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ protected void doStartForeground(Bundle extras) {
107107
Context context = getApplicationContext();
108108
Intent contextIntent = new Intent(context, PythonActivity.class);
109109
PendingIntent pIntent = PendingIntent.getActivity(context, 0, contextIntent,
110-
PendingIntent.FLAG_UPDATE_CURRENT);
110+
PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT);
111111

112112
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
113113
notification = new Notification(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package org.kivy.android;
2+
3+
import android.content.BroadcastReceiver;
4+
import android.content.Intent;
5+
import android.content.Context;
6+
7+
public class GenericBroadcastReceiver extends BroadcastReceiver {
8+
9+
GenericBroadcastReceiverCallback listener;
10+
11+
public GenericBroadcastReceiver(GenericBroadcastReceiverCallback listener) {
12+
super();
13+
this.listener = listener;
14+
}
15+
16+
public void onReceive(Context context, Intent intent) {
17+
this.listener.onReceive(context, intent);
18+
}
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package org.kivy.android;
2+
3+
import android.content.Intent;
4+
import android.content.Context;
5+
6+
public interface GenericBroadcastReceiverCallback {
7+
void onReceive(Context context, Intent intent);
8+
};

pythonforandroid/bootstraps/service_library/build/templates/Service.tmpl.java

Lines changed: 42 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,42 @@ public class Service{{ name|capitalize }} extends PythonService {
1515

1616
private static final String TAG = "PythonService";
1717

18+
{% if sticky %}
19+
@Override
20+
public int startType() {
21+
return START_STICKY;
22+
}
23+
{% endif %}
24+
25+
@Override
26+
protected int getServiceId() {
27+
return {{ service_id }};
28+
}
29+
1830
public static void prepare(Context ctx) {
1931
String appRoot = PythonUtil.getAppRoot(ctx);
2032
Log.v(TAG, "Ready to unpack");
2133
File app_root_file = new File(appRoot);
22-
PythonUtil.unpackData(ctx, "private", app_root_file, false);
34+
PythonUtil.unpackAsset(ctx, "private", app_root_file, true);
35+
PythonUtil.unpackPyBundle(ctx, ctx.getApplicationInfo().nativeLibraryDir + "/" + "libpybundle", app_root_file, false);
2336
}
2437

2538
public static void start(Context ctx, String pythonServiceArgument) {
39+
Intent intent = getDefaultIntent(ctx, pythonServiceArgument);
40+
41+
//foreground: {{foreground}}
42+
{% if foreground %}
43+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
44+
ctx.startForegroundService(intent);
45+
} else {
46+
ctx.startService(intent);
47+
}
48+
{% else %}
49+
ctx.startService(intent);
50+
{% endif %}
51+
}
52+
53+
static public Intent getDefaultIntent(Context ctx, String pythonServiceArgument) {
2654
String appRoot = PythonUtil.getAppRoot(ctx);
2755
Intent intent = new Intent(ctx, Service{{ name|capitalize }}.class);
2856
intent.putExtra("androidPrivate", appRoot);
@@ -36,16 +64,19 @@ public static void start(Context ctx, String pythonServiceArgument) {
3664
intent.putExtra("androidUnpack", appRoot);
3765
intent.putExtra("pythonPath", appRoot + ":" + appRoot + "/lib");
3866
intent.putExtra("pythonServiceArgument", pythonServiceArgument);
67+
return intent;
68+
}
3969

40-
//foreground: {{foreground}}
41-
{% if foreground %}
42-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
43-
ctx.startForegroundService(intent);
44-
} else {
45-
ctx.startService(intent);
46-
}
47-
{% else %}
48-
ctx.startService(intent);
49-
{% endif %}
70+
@Override
71+
protected Intent getThisDefaultIntent(Context ctx, String pythonServiceArgument) {
72+
return Service{{ name|capitalize }}.getDefaultIntent(ctx, pythonServiceArgument);
73+
}
74+
75+
76+
77+
static public void stop(Context ctx) {
78+
Intent intent = new Intent(ctx, Service{{ name|capitalize }}.class);
79+
ctx.stopService(intent);
5080
}
81+
5182
}

pythonforandroid/bootstraps/service_only/__init__.py

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -24,31 +24,28 @@ def assemble_distribution(self):
2424
with open('local.properties', 'w') as fileh:
2525
fileh.write('sdk.dir={}'.format(self.ctx.sdk_dir))
2626

27-
arch = self.ctx.archs[0]
28-
if len(self.ctx.archs) > 1:
29-
raise ValueError('built for more than one arch, but bootstrap cannot handle that yet')
30-
info('Bootstrap running with arch {}'.format(arch))
31-
3227
with current_directory(self.dist_dir):
3328
info('Copying python distribution')
3429

35-
self.distribute_libs(arch, [self.ctx.get_libs_dir(arch.arch)])
36-
self.distribute_aars(arch)
3730
self.distribute_javaclasses(self.ctx.javaclass_dir,
3831
dest_dir=join("src", "main", "java"))
3932

40-
python_bundle_dir = join(f'_python_bundle__{arch.arch}', '_python_bundle')
41-
ensure_dir(python_bundle_dir)
42-
site_packages_dir = self.ctx.python_recipe.create_python_bundle(
43-
join(self.dist_dir, python_bundle_dir), arch)
33+
for arch in self.ctx.archs:
34+
self.distribute_libs(arch, [self.ctx.get_libs_dir(arch.arch)])
35+
self.distribute_aars(arch)
36+
37+
python_bundle_dir = join(f'_python_bundle__{arch.arch}', '_python_bundle')
38+
ensure_dir(python_bundle_dir)
39+
site_packages_dir = self.ctx.python_recipe.create_python_bundle(
40+
join(self.dist_dir, python_bundle_dir), arch)
41+
if not self.ctx.with_debug_symbols:
42+
self.strip_libraries(arch)
43+
self.fry_eggs(site_packages_dir)
4444

4545
if 'sqlite3' not in self.ctx.recipe_build_order:
4646
with open('blacklist.txt', 'a') as fileh:
4747
fileh.write('\nsqlite3/*\nlib-dynload/_sqlite3.so\n')
4848

49-
if not self.ctx.with_debug_symbols:
50-
self.strip_libraries(arch)
51-
self.fry_eggs(site_packages_dir)
5249
super().assemble_distribution()
5350

5451

pythonforandroid/toolchain.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1089,7 +1089,7 @@ def _build_package(self, args, package_type):
10891089
)
10901090
gradle_task = "assembleDebug"
10911091
elif args.build_mode == "release":
1092-
if package_type == "apk":
1092+
if package_type in ["apk", "aar"]:
10931093
gradle_task = "assembleRelease"
10941094
elif package_type == "aab":
10951095
gradle_task = "bundleRelease"

testapps/on_device_unit_tests/setup.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,17 @@
6464
'permissions': ['INTERNET', 'VIBRATE'],
6565
'orientation': 'sensor',
6666
'service': 'P4a_test_service:app_service.py',
67+
},
68+
'aar':
69+
{
70+
'requirements' : 'python3',
71+
'android-api': 27,
72+
'ndk-api': 21,
73+
'dist-name': 'bdist_unit_tests_app',
74+
'arch': 'arm64-v8a',
75+
'bootstrap' : 'service_library',
76+
'permissions': ['INTERNET', 'VIBRATE'],
77+
'service': 'P4a_test_service:app_service.py',
6778
}
6879
}
6980

0 commit comments

Comments
 (0)