Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added few input parameters to make possible to use custom java classes and tweak AndroidManifest.xml #2338

Merged
merged 1 commit into from
Feb 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion pythonforandroid/bootstraps/common/build/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@ def get_bootstrap_name():
join(curdir, 'templates')))


DEFAULT_PYTHON_ACTIVITY_JAVA_CLASS = 'org.kivy.android.PythonActivity'
DEFAULT_PYTHON_SERVICE_JAVA_CLASS = 'org.kivy.android.PythonService'


def ensure_dir(path):
if not exists(path):
makedirs(path)
Expand Down Expand Up @@ -430,6 +434,7 @@ def make_package(args):
service = True

service_names = []
base_service_class = args.service_class_name.split('.')[-1]
for sid, spec in enumerate(args.services):
spec = spec.split(':')
name = spec[0]
Expand All @@ -454,6 +459,7 @@ def make_package(args):
foreground=foreground,
sticky=sticky,
service_id=sid + 1,
base_service_class=base_service_class,
)

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

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

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

args = ap.parse_args(args)

args.ignore_path = []

if args.name and args.name[0] == '"' and args.name[-1] == '"':
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

import android.content.Intent;
import android.content.Context;
import org.kivy.android.PythonService;
import {{ args.service_class_name }};


public class Service{{ name|capitalize }} extends PythonService {
public class Service{{ name|capitalize }} extends {{ base_service_class }} {
{% if sticky %}
@Override
public int startType() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,10 @@
android:icon="@drawable/icon"
android:allowBackup="{{ args.allow_backup }}"
{% if args.backup_rules %}android:fullBackupContent="@xml/{{ args.backup_rules }}"{% endif %}
{{ args.extra_manifest_application_arguments }}
android:theme="{{args.android_apptheme}}{% if not args.window %}.Fullscreen{% endif %}"
android:hardwareAccelerated="true" >
android:hardwareAccelerated="true"
>
{% for l in args.android_used_libs %}
<uses-library android:name="{{ l }}" />
{% endfor %}
Expand Down Expand Up @@ -110,7 +112,7 @@
{% endif %}

{% if service or args.launcher %}
<service android:name="org.kivy.android.PythonService"
<service android:name="{{ args.service_class_name }}"
android:process=":pythonservice" />
{% endif %}
{% for name in service_names %}
Expand Down
1 change: 1 addition & 0 deletions pythonforandroid/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,7 @@ def __init__(self):
self.copy_libs = False

self.activity_class_name = u'org.kivy.android.PythonActivity'
self.service_class_name = u'org.kivy.android.PythonService'

# this list should contain all Archs, it is pruned later
self.archs = (
Expand Down
1 change: 1 addition & 0 deletions pythonforandroid/recipes/android/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ def prebuild_arch(self, arch):
'JNI_NAMESPACE': jni_ns,
'ACTIVITY_CLASS_NAME': self.ctx.activity_class_name,
'ACTIVITY_CLASS_NAMESPACE': self.ctx.activity_class_name.replace('.', '/'),
'SERVICE_CLASS_NAME': self.ctx.service_class_name,
}

# create config files for Cython, C and Python
Expand Down
4 changes: 2 additions & 2 deletions pythonforandroid/recipes/android/src/android/broadcast.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# Broadcast receiver bridge

from jnius import autoclass, PythonJavaClass, java_method
from android.config import JAVA_NAMESPACE, JNI_NAMESPACE, ACTIVITY_CLASS_NAME
from android.config import JAVA_NAMESPACE, JNI_NAMESPACE, ACTIVITY_CLASS_NAME, SERVICE_CLASS_NAME


class BroadcastReceiver(object):
Expand Down Expand Up @@ -72,7 +72,7 @@ def stop(self):
def context(self):
from os import environ
if 'PYTHON_SERVICE_ARGUMENT' in environ:
PythonService = autoclass(JAVA_NAMESPACE + '.PythonService')
PythonService = autoclass(SERVICE_CLASS_NAME)
return PythonService.mService
PythonActivity = autoclass(ACTIVITY_CLASS_NAME)
return PythonActivity.mActivity
4 changes: 2 additions & 2 deletions pythonforandroid/recipes/android/src/android/storage.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from jnius import autoclass, cast
import os

from android.config import JAVA_NAMESPACE, ACTIVITY_CLASS_NAME
from android.config import ACTIVITY_CLASS_NAME, SERVICE_CLASS_NAME


Environment = autoclass('android.os.Environment')
Expand Down Expand Up @@ -34,7 +34,7 @@ def _get_activity():
activity = PythonActivity.mActivity
if activity is None:
# assume we're running from the background service
PythonService = autoclass(JAVA_NAMESPACE + '.' + 'PythonService')
PythonService = autoclass(SERVICE_CLASS_NAME)
activity = PythonService.mService
return activity

Expand Down
10 changes: 10 additions & 0 deletions pythonforandroid/toolchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,11 @@ def __init__(self):
dest='activity_class_name', default='org.kivy.android.PythonActivity',
help='The full java class name of the main activity')

generic_parser.add_argument(
'--service-class-name',
dest='service_class_name', default='org.kivy.android.PythonService',
help='Full java package name of the PythonService class')

generic_parser.add_argument(
'--java-build-tool',
dest='java_build_tool', default='auto',
Expand Down Expand Up @@ -613,6 +618,10 @@ def add_parser(subparsers, *args, **kwargs):
args.unknown_args += ["--with-debug-symbols"]
if hasattr(args, "ignore_setup_py") and args.ignore_setup_py:
args.use_setup_py = False
if hasattr(args, "activity_class_name") and args.activity_class_name != 'org.kivy.android.PythonActivity':
args.unknown_args += ["--activity-class-name", args.activity_class_name]
if hasattr(args, "service_class_name") and args.service_class_name != 'org.kivy.android.PythonService':
args.unknown_args += ["--service-class-name", args.service_class_name]

self.args = args

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

self.ctx.activity_class_name = args.activity_class_name
self.ctx.service_class_name = args.service_class_name

# Each subparser corresponds to a method
command = args.subparser_name.replace('-', '_')
Expand Down
39 changes: 39 additions & 0 deletions tests/test_build.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import unittest
from unittest import mock

import jinja2

from pythonforandroid.build import run_pymodules_install


Expand Down Expand Up @@ -48,3 +50,40 @@ def test_strip_if_with_debug_symbols(self):
ctx.with_debug_symbols = False
assert run_pymodules_install(ctx, modules, project_dir) is None
assert m_CythonRecipe().strip_object_files.called is True


class TestTemplates(unittest.TestCase):

def test_android_manifest_xml(self):
args = mock.Mock()
args.min_sdk_version = 12
args.build_mode = 'debug'
args.native_services = ['abcd', ]
args.permissions = []
args.add_activity = []
args.android_used_libs = []
args.meta_data = []
args.extra_manifest_xml = '<tag-a><tag-b></tag-b></tag-a>'
args.extra_manifest_application_arguments = 'android:someParameter="true" android:anotherParameter="false"'
render_args = {
"args": args,
"service": False,
"service_names": [],
"android_api": 1234,
"debug": "debug" in args.build_mode,
"native_services": args.native_services
}
environment = jinja2.Environment(
loader=jinja2.FileSystemLoader('pythonforandroid/bootstraps/sdl2/build/templates/')
)
template = environment.get_template('AndroidManifest.tmpl.xml')
xml = template.render(**render_args)
assert xml.count('android:minSdkVersion="12"') == 1
assert xml.count('android:anotherParameter="false"') == 1
assert xml.count('android:someParameter="true"') == 1
assert xml.count('<tag-a><tag-b></tag-b></tag-a>') == 1
assert xml.count('android:process=":service_') == 0
assert xml.count('targetSdkVersion="1234"') == 1
assert xml.count('android:debuggable="true"') == 1
assert xml.count('<service android:name="abcd" />') == 1
# TODO: potentially some other checks to be added here to cover other "logic" (flags and loops) in the template
2 changes: 2 additions & 0 deletions tests/test_toolchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ def test_create(self):
'--requirements=python3',
'--dist-name=test_toolchain',
'--activity-class-name=abc.myapp.android.CustomPythonActivity',
'--service-class-name=xyz.myapp.android.CustomPythonService',
]
with patch_sys_argv(argv), mock.patch(
'pythonforandroid.build.get_available_apis'
Expand All @@ -80,6 +81,7 @@ def test_create(self):
'/tmp/android-ndk/platforms/android-21/arch-arm', True)
tchain = ToolchainCL()
assert tchain.ctx.activity_class_name == 'abc.myapp.android.CustomPythonActivity'
assert tchain.ctx.service_class_name == 'xyz.myapp.android.CustomPythonService'
assert m_get_available_apis.call_args_list in [
[mock.call('/tmp/android-sdk')], # linux case
[mock.call('/private/tmp/android-sdk')] # macos case
Expand Down