Skip to content

Commit d287bbc

Browse files
committed
Update
1 parent c87c243 commit d287bbc

10 files changed

Lines changed: 125 additions & 23 deletions

File tree

.github/workflows/buildozer_android_action.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ jobs:
3333
- name: Cache Buildozer directory in app
3434
uses: actions/cache@v4
3535
with:
36-
path: client/.buildozer
36+
path: .buildozer
3737
key: ${{ runner.os }}-buildozer-app
3838
restore-keys: |
3939
${{ runner.os }}-buildozer-app
@@ -51,6 +51,7 @@ jobs:
5151
run: |
5252
sudo apt update
5353
sudo apt-get install -y \
54+
ant \
5455
build-essential \
5556
git \
5657
ffmpeg \
@@ -133,4 +134,4 @@ jobs:
133134
name: package
134135
path: |
135136
client/bin/*.apk
136-
client/bin/*.aab
137+
client/bin/*.aab

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2025 Kartavya Shukla
3+
Copyright (c) 2025-2026 Kartavya Shukla
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

README.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,46 @@ Download and extract debuggable package.zip from the [latest workflow run](https
6363

6464
[Live Demo](https://youtu.be/-VTCTNmHB94)
6565

66+
**Pre-installed libs:**
67+
- kivy
68+
- carbonkivy
69+
- plyer
70+
- pyjnius
71+
- requests
72+
- android
73+
- kaki
74+
- watchdog
75+
- sqlite3
76+
- pygments
77+
- pillow
78+
79+
**Available permissions in manifest you can ask for during runtime:**
80+
81+
```
82+
android.permission.INTERNET
83+
android.permission.ACCESS_NETWORK_STATE
84+
android.permission.WAVE_LOCK
85+
android.permission.READ_EXTERNAL_STORAGE
86+
android.permission.WRITE_EXTERNAL_STORAGE
87+
android.permission.CAMERA
88+
android.permission.READ_MEDIA_IMAGES
89+
android.permission.READ_MEDIA_AUDIO
90+
android.permission.READ_MEDIA_VIDEO
91+
android.permission.ACCESS_FINE_LOCATION
92+
android.permission.ACCESS_COARSE_LOCATION
93+
android.permission.ACCESS_BACKGROUND_LOCATION
94+
android.permission.READ_PHONE_STATE
95+
android.permission.SCHEDULE_EXACT_ALARM
96+
android.permission.POST_NOTIFICATIONS
97+
android.permission.ACCESS_WIFI_STATE
98+
android.permission.VIBRATE
99+
android.permission.FLASHLIGHT
100+
android.permission.RECORD_AUDIO
101+
android.permission.BLUETOOTH
102+
android.permission.USE_BIOMETRIC
103+
android.permission.USE_FINGERPRINT
104+
```
105+
66106

67107
## Part of KvDeveloper Ecosystem
68108
KvDeveloper Client is a subproject under the [KvDeveloper](https://github.com/Novfensec/KvDeveloper) initiative. The ecosystem aims to streamline Python-powered mobile workflows with modern tooling.

client/View/HomeScreen/home_screen.kv

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@
9898
icon: "connect"
9999
role: "Large Productive"
100100
on_press:
101-
app.launch(ServerUrlEntry.text)
101+
root.screen.launch(ServerUrlEntry.text)
102102

103103
CDivider:
104104

@@ -163,5 +163,4 @@
163163
UIShellButton:
164164
icon: "play"
165165
on_press:
166-
app.launch(root.name)
167-
166+
root.launch(root.name)

client/View/HomeScreen/home_screen.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,25 @@
22

33
from kivy.properties import StringProperty
44

5-
from carbonkivy.uix.notification import CNotificationToast
5+
from carbonkivy.app import CarbonApp
66
from carbonkivy.uix.boxlayout import CBoxLayout
77

8+
from kivy.clock import Clock
9+
810
from View.base_screen import BaseScreenView
911

1012

1113
class ServerTile(CBoxLayout):
1214

1315
name = StringProperty()
1416

17+
def __init__(self, *args, **kwargs):
18+
super(ServerTile, self).__init__(*args, **kwargs)
19+
self.app = CarbonApp.get_running_app()
20+
21+
def launch(self, url: str, *args) -> None:
22+
Clock.schedule_once(lambda dt, y=url: self.app.launch(y))
23+
1524

1625
class HomeScreenView(BaseScreenView):
1726

@@ -22,6 +31,9 @@ def on_kv_post(self, base_widget):
2231
self.fetch_saved()
2332
return super().on_kv_post(base_widget)
2433

34+
def launch(self, url: str, *args) -> None:
35+
Clock.schedule_once(lambda dt, y=url: self.app.launch(y))
36+
2537
def fetch_saved(self, *args) -> None:
2638
json_path = os.path.join(self.app.directory, "data", "servers.json")
2739
if os.path.exists(json_path):

client/View/InstallerScreen/installer_screen.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,11 @@ def __init__(self, *args, **kwargs) -> None:
1111
super(InstallerScreenView, self).__init__(*args, **kwargs)
1212

1313
def install_package(self, package_name: str) -> None:
14-
from libs.installer import install
15-
threading.Thread(
16-
target=lambda: install(package_name=package_name), daemon=True
17-
).start()
14+
# from libs.installer import install
15+
# threading.Thread(
16+
# target=lambda: install(package_name=package_name), daemon=True
17+
# ).start()
18+
self.notify_info()
1819

1920
def notify_info(self, *args) -> None:
2021
self.app.notify(

client/buildozer.spec

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ version = 0.2
4242

4343
# (list) Application requirements
4444
# comma separated e.g. requirements = sqlite3,kivy
45-
requirements = python3, kivy==2.3.1, https://github.com/CarbonKivy/CarbonKivy/archive/docs.zip, android, requests, pyjnius, kaki, watchdog, pygments
45+
requirements = python3, kivy==2.3.1, https://github.com/CarbonKivy/CarbonKivy/archive/master.zip, android, requests, pyjnius, kaki, watchdog, pygments, plyer, sqlite3, pillow
4646

4747
# (str) Custom source folders for requirements
4848
# Sets custom source for any requirements with recipes
@@ -56,7 +56,7 @@ icon.filename = %(source.dir)s/assets/images/kvdeveloper_logo512.png
5656

5757
# (list) Supported orientations
5858
# Valid options are: landscape, portrait, portrait-reverse, landscape-reverse, or all
59-
orientation = portrait
59+
orientation = all
6060

6161
# (list) List of services to declare
6262
# This is currently only relevant to Android services.
@@ -104,7 +104,30 @@ android.presplash_color = #000000
104104

105105
# (list) Permissions
106106
# (See https://python-for-android.readthedocs.io/en/latest/buildoptions.html for all the supported syntaxes and properties)
107-
android.permissions = android.permission.INTERNET, android.permission.ACCESS_NETWORK_STATE, android.permission.WAVE_LOCK, android.permission.MANAGE_EXTERNAL_STORAGE, android.permission.READ_EXTERNAL_STORAGE, android.permission.WRITE_EXTERNAL_STORAGE, android.permission.CAMERA
107+
[app:android.permissions]
108+
android.permission.INTERNET
109+
android.permission.ACCESS_NETWORK_STATE
110+
android.permission.WAVE_LOCK
111+
android.permission.READ_EXTERNAL_STORAGE
112+
android.permission.WRITE_EXTERNAL_STORAGE
113+
android.permission.CAMERA
114+
android.permission.READ_MEDIA_IMAGES
115+
android.permission.READ_MEDIA_AUDIO
116+
android.permission.READ_MEDIA_VIDEO
117+
android.permission.ACCESS_FINE_LOCATION
118+
android.permission.ACCESS_COARSE_LOCATION
119+
android.permission.ACCESS_BACKGROUND_LOCATION
120+
android.permission.READ_PHONE_STATE
121+
android.permission.SCHEDULE_EXACT_ALARM
122+
android.permission.POST_NOTIFICATIONS
123+
android.permission.ACCESS_WIFI_STATE
124+
android.permission.VIBRATE
125+
android.permission.FLASHLIGHT
126+
android.permission.RECORD_AUDIO
127+
android.permission.BLUETOOTH
128+
android.permission.USE_BIOMETRIC
129+
android.permission.USE_FINGERPRINT
130+
108131

109132
# (list) features (adds uses-feature -tags to manifest)
110133
#android.features = android.hardware.usb.host
@@ -113,7 +136,7 @@ android.permissions = android.permission.INTERNET, android.permission.ACCESS_NET
113136
android.api = 36
114137

115138
# (int) Minimum API your APK / AAB will support.
116-
android.minapi = 28
139+
android.minapi = 32
117140

118141
# (int) Android SDK version to use
119142
#android.sdk = 20
@@ -122,7 +145,7 @@ android.minapi = 28
122145
android.ndk = 28c
123146

124147
# (int) Android NDK API to use. This is the minimum API your app will support, it should usually match android.minapi.
125-
#android.ndk_api = 21
148+
#android.ndk_api = 32
126149

127150
# (str) Android NDK directory (if empty, it will be automatically downloaded.)
128151
#android.ndk_path =
@@ -318,16 +341,16 @@ android.allow_backup = True
318341
# android.no-byte-compile-python = False
319342

320343
# (str) The format used to package the app for release mode (aab or apk or aar).
321-
# android.release_artifact = aab
344+
android.release_artifact = aab
322345

323346
# (str) The format used to package the app for debug mode (apk or aar).
324-
# android.debug_artifact = apk
347+
android.debug_artifact = apk
325348

326349
# (str) A display cutout is an area on some devices that extends into the display surface.
327350
# It allows for an edge-to-edge experience while providing space for important sensors on the front of the device.
328351
# Available options for Android API >= 28 are "default, shortEdges, never" and defaults to never.
329352
# Android documentation: https://developer.android.com/develop/ui/views/layout/display-cutout
330-
#android.display_cutout = never
353+
android.display_cutout = shortEdges
331354

332355
#
333356
# Python for android (p4a) specific

client/libs/launcher/__init__.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from libs.launcher.android import (
2222
AppStorageDir,
2323
launch_client_activity,
24+
stop_client_activity,
2425
)
2526

2627

@@ -204,13 +205,16 @@ def run_entrypoint(self) -> None:
204205
)
205206

206207
def restart_entrypoint(self) -> None:
207-
if platform == "windows":
208+
print("[RESTART] Killing previous process...")
209+
if platform == "win":
208210
if self.process and self.process.poll() is None:
209-
print("[RESTART] Killing previous process...")
210211
self.process.terminate()
211212
self.process.wait()
212-
print(f"[RESTART] Restarting {self.entrypoint}")
213-
self.run_entrypoint()
213+
elif platform == "android":
214+
stop_client_activity()
215+
216+
print(f"[RESTART] Restarting {self.entrypoint}")
217+
self.run_entrypoint()
214218

215219
@mainthread
216220
def display_indicator(self, val: bool = True, *args) -> None:

client/libs/launcher/android/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,9 @@ def launch_client_activity(entrypoint_path: str) -> None:
1919
intent.setData(uri)
2020
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK)
2121
activity.startActivity(intent)
22+
23+
@run_on_ui_thread
24+
def stop_client_activity() -> None:
25+
activity_instance = ClientActivity.getInstance()
26+
if activity_instance:
27+
activity_instance.finish()

client/src/org/kvdeveloper/client/ClientActivity.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,27 @@
99

1010
public class ClientActivity extends PythonActivity {
1111
private static final String TAG = "ClientActivity";
12+
// Static reference to the current instance
13+
14+
private static ClientActivity instance;
1215

1316
@Override
1417
protected void onCreate(Bundle savedInstanceState) {
1518
Log.i(TAG, "ClientActivity started");
1619
super.onCreate(savedInstanceState);
20+
instance = this;
21+
}
22+
23+
public static ClientActivity getInstance() {
24+
return instance;
25+
}
26+
27+
@Override
28+
protected void onDestroy() {
29+
super.onDestroy();
30+
if (instance == this) {
31+
instance = null; // clear reference
32+
}
1733
}
1834

1935
@Override

0 commit comments

Comments
 (0)