Skip to content

Commit ab65c48

Browse files
authored
Merge pull request kivy#2338 from vesellov/develop
added few input parameters to make possible to use custom java classes and tweak AndroidManifest.xml
2 parents fe5d722 + 49de421 commit ab65c48

File tree

10 files changed

+78
-9
lines changed

10 files changed

+78
-9
lines changed

pythonforandroid/bootstraps/common/build/build.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,10 @@ def get_bootstrap_name():
8989
join(curdir, 'templates')))
9090

9191

92+
DEFAULT_PYTHON_ACTIVITY_JAVA_CLASS = 'org.kivy.android.PythonActivity'
93+
DEFAULT_PYTHON_SERVICE_JAVA_CLASS = 'org.kivy.android.PythonService'
94+
95+
9296
def ensure_dir(path):
9397
if not exists(path):
9498
makedirs(path)
@@ -430,6 +434,7 @@ def make_package(args):
430434
service = True
431435

432436
service_names = []
437+
base_service_class = args.service_class_name.split('.')[-1]
433438
for sid, spec in enumerate(args.services):
434439
spec = spec.split(':')
435440
name = spec[0]
@@ -454,6 +459,7 @@ def make_package(args):
454459
foreground=foreground,
455460
sticky=sticky,
456461
service_id=sid + 1,
462+
base_service_class=base_service_class,
457463
)
458464

459465
# Find the SDK directory and target API
@@ -701,7 +707,7 @@ def parse_args_and_make_package(args=None):
701707
'activity-element.html'))
702708

703709
ap.add_argument('--android-entrypoint', dest='android_entrypoint',
704-
default='org.kivy.android.PythonActivity',
710+
default=DEFAULT_PYTHON_ACTIVITY_JAVA_CLASS,
705711
help='Defines which java class will be used for startup, usually a subclass of PythonActivity')
706712
ap.add_argument('--android-apptheme', dest='android_apptheme',
707713
default='@android:style/Theme.NoTitleBar',
@@ -800,9 +806,16 @@ def parse_args_and_make_package(args=None):
800806
ap.add_argument('--extra-manifest-xml', default='',
801807
help=('Extra xml to write directly inside the <manifest> element of'
802808
'AndroidManifest.xml'))
809+
ap.add_argument('--extra-manifest-application-arguments', default='',
810+
help='Extra arguments to be added to the <manifest><application> tag of'
811+
'AndroidManifest.xml')
803812
ap.add_argument('--manifest-placeholders', dest='manifest_placeholders',
804813
default='[:]', help=('Inject build variables into the manifest '
805814
'via the manifestPlaceholders property'))
815+
ap.add_argument('--service-class-name', dest='service_class_name', default=DEFAULT_PYTHON_SERVICE_JAVA_CLASS,
816+
help='Use that parameter if you need to implement your own PythonServive Java class')
817+
ap.add_argument('--activity-class-name', dest='activity_class_name', default=DEFAULT_PYTHON_ACTIVITY_JAVA_CLASS,
818+
help='The full java class name of the main activity')
806819

807820
# Put together arguments, and add those from .p4a config file:
808821
if args is None:
@@ -822,6 +835,7 @@ def _read_configuration():
822835
_read_configuration()
823836

824837
args = ap.parse_args(args)
838+
825839
args.ignore_path = []
826840

827841
if args.name and args.name[0] == '"' and args.name[-1] == '"':

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22

33
import android.content.Intent;
44
import android.content.Context;
5-
import org.kivy.android.PythonService;
5+
import {{ args.service_class_name }};
66

77

8-
public class Service{{ name|capitalize }} extends PythonService {
8+
public class Service{{ name|capitalize }} extends {{ base_service_class }} {
99
{% if sticky %}
1010
@Override
1111
public int startType() {

pythonforandroid/bootstraps/sdl2/build/templates/AndroidManifest.tmpl.xml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,10 @@
5959
android:icon="@drawable/icon"
6060
android:allowBackup="{{ args.allow_backup }}"
6161
{% if args.backup_rules %}android:fullBackupContent="@xml/{{ args.backup_rules }}"{% endif %}
62+
{{ args.extra_manifest_application_arguments }}
6263
android:theme="{{args.android_apptheme}}{% if not args.window %}.Fullscreen{% endif %}"
63-
android:hardwareAccelerated="true" >
64+
android:hardwareAccelerated="true"
65+
>
6466
{% for l in args.android_used_libs %}
6567
<uses-library android:name="{{ l }}" />
6668
{% endfor %}
@@ -110,7 +112,7 @@
110112
{% endif %}
111113

112114
{% if service or args.launcher %}
113-
<service android:name="org.kivy.android.PythonService"
115+
<service android:name="{{ args.service_class_name }}"
114116
android:process=":pythonservice" />
115117
{% endif %}
116118
{% for name in service_names %}

pythonforandroid/build.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,7 @@ def __init__(self):
448448
self.copy_libs = False
449449

450450
self.activity_class_name = u'org.kivy.android.PythonActivity'
451+
self.service_class_name = u'org.kivy.android.PythonService'
451452

452453
# this list should contain all Archs, it is pruned later
453454
self.archs = (

pythonforandroid/recipes/android/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ def prebuild_arch(self, arch):
5353
'JNI_NAMESPACE': jni_ns,
5454
'ACTIVITY_CLASS_NAME': self.ctx.activity_class_name,
5555
'ACTIVITY_CLASS_NAMESPACE': self.ctx.activity_class_name.replace('.', '/'),
56+
'SERVICE_CLASS_NAME': self.ctx.service_class_name,
5657
}
5758

5859
# create config files for Cython, C and Python

pythonforandroid/recipes/android/src/android/broadcast.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# Broadcast receiver bridge
33

44
from jnius import autoclass, PythonJavaClass, java_method
5-
from android.config import JAVA_NAMESPACE, JNI_NAMESPACE, ACTIVITY_CLASS_NAME
5+
from android.config import JAVA_NAMESPACE, JNI_NAMESPACE, ACTIVITY_CLASS_NAME, SERVICE_CLASS_NAME
66

77

88
class BroadcastReceiver(object):
@@ -72,7 +72,7 @@ def stop(self):
7272
def context(self):
7373
from os import environ
7474
if 'PYTHON_SERVICE_ARGUMENT' in environ:
75-
PythonService = autoclass(JAVA_NAMESPACE + '.PythonService')
75+
PythonService = autoclass(SERVICE_CLASS_NAME)
7676
return PythonService.mService
7777
PythonActivity = autoclass(ACTIVITY_CLASS_NAME)
7878
return PythonActivity.mActivity

pythonforandroid/recipes/android/src/android/storage.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from jnius import autoclass, cast
22
import os
33

4-
from android.config import JAVA_NAMESPACE, ACTIVITY_CLASS_NAME
4+
from android.config import ACTIVITY_CLASS_NAME, SERVICE_CLASS_NAME
55

66

77
Environment = autoclass('android.os.Environment')
@@ -34,7 +34,7 @@ def _get_activity():
3434
activity = PythonActivity.mActivity
3535
if activity is None:
3636
# assume we're running from the background service
37-
PythonService = autoclass(JAVA_NAMESPACE + '.' + 'PythonService')
37+
PythonService = autoclass(SERVICE_CLASS_NAME)
3838
activity = PythonService.mService
3939
return activity
4040

pythonforandroid/toolchain.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,11 @@ def __init__(self):
380380
dest='activity_class_name', default='org.kivy.android.PythonActivity',
381381
help='The full java class name of the main activity')
382382

383+
generic_parser.add_argument(
384+
'--service-class-name',
385+
dest='service_class_name', default='org.kivy.android.PythonService',
386+
help='Full java package name of the PythonService class')
387+
383388
generic_parser.add_argument(
384389
'--java-build-tool',
385390
dest='java_build_tool', default='auto',
@@ -613,6 +618,10 @@ def add_parser(subparsers, *args, **kwargs):
613618
args.unknown_args += ["--with-debug-symbols"]
614619
if hasattr(args, "ignore_setup_py") and args.ignore_setup_py:
615620
args.use_setup_py = False
621+
if hasattr(args, "activity_class_name") and args.activity_class_name != 'org.kivy.android.PythonActivity':
622+
args.unknown_args += ["--activity-class-name", args.activity_class_name]
623+
if hasattr(args, "service_class_name") and args.service_class_name != 'org.kivy.android.PythonService':
624+
args.unknown_args += ["--service-class-name", args.service_class_name]
616625

617626
self.args = args
618627

@@ -709,6 +718,7 @@ def add_parser(subparsers, *args, **kwargs):
709718
self.ctx.copy_libs = args.copy_libs
710719

711720
self.ctx.activity_class_name = args.activity_class_name
721+
self.ctx.service_class_name = args.service_class_name
712722

713723
# Each subparser corresponds to a method
714724
command = args.subparser_name.replace('-', '_')

tests/test_build.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import unittest
22
from unittest import mock
33

4+
import jinja2
5+
46
from pythonforandroid.build import run_pymodules_install
57

68

@@ -48,3 +50,40 @@ def test_strip_if_with_debug_symbols(self):
4850
ctx.with_debug_symbols = False
4951
assert run_pymodules_install(ctx, modules, project_dir) is None
5052
assert m_CythonRecipe().strip_object_files.called is True
53+
54+
55+
class TestTemplates(unittest.TestCase):
56+
57+
def test_android_manifest_xml(self):
58+
args = mock.Mock()
59+
args.min_sdk_version = 12
60+
args.build_mode = 'debug'
61+
args.native_services = ['abcd', ]
62+
args.permissions = []
63+
args.add_activity = []
64+
args.android_used_libs = []
65+
args.meta_data = []
66+
args.extra_manifest_xml = '<tag-a><tag-b></tag-b></tag-a>'
67+
args.extra_manifest_application_arguments = 'android:someParameter="true" android:anotherParameter="false"'
68+
render_args = {
69+
"args": args,
70+
"service": False,
71+
"service_names": [],
72+
"android_api": 1234,
73+
"debug": "debug" in args.build_mode,
74+
"native_services": args.native_services
75+
}
76+
environment = jinja2.Environment(
77+
loader=jinja2.FileSystemLoader('pythonforandroid/bootstraps/sdl2/build/templates/')
78+
)
79+
template = environment.get_template('AndroidManifest.tmpl.xml')
80+
xml = template.render(**render_args)
81+
assert xml.count('android:minSdkVersion="12"') == 1
82+
assert xml.count('android:anotherParameter="false"') == 1
83+
assert xml.count('android:someParameter="true"') == 1
84+
assert xml.count('<tag-a><tag-b></tag-b></tag-a>') == 1
85+
assert xml.count('android:process=":service_') == 0
86+
assert xml.count('targetSdkVersion="1234"') == 1
87+
assert xml.count('android:debuggable="true"') == 1
88+
assert xml.count('<service android:name="abcd" />') == 1
89+
# TODO: potentially some other checks to be added here to cover other "logic" (flags and loops) in the template

tests/test_toolchain.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ def test_create(self):
6161
'--requirements=python3',
6262
'--dist-name=test_toolchain',
6363
'--activity-class-name=abc.myapp.android.CustomPythonActivity',
64+
'--service-class-name=xyz.myapp.android.CustomPythonService',
6465
]
6566
with patch_sys_argv(argv), mock.patch(
6667
'pythonforandroid.build.get_available_apis'
@@ -80,6 +81,7 @@ def test_create(self):
8081
'/tmp/android-ndk/platforms/android-21/arch-arm', True)
8182
tchain = ToolchainCL()
8283
assert tchain.ctx.activity_class_name == 'abc.myapp.android.CustomPythonActivity'
84+
assert tchain.ctx.service_class_name == 'xyz.myapp.android.CustomPythonService'
8385
assert m_get_available_apis.call_args_list in [
8486
[mock.call('/tmp/android-sdk')], # linux case
8587
[mock.call('/private/tmp/android-sdk')] # macos case

0 commit comments

Comments
 (0)