enpaf 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- enpaf-1.0.0/LICENSE +21 -0
- enpaf-1.0.0/MANIFEST.in +19 -0
- enpaf-1.0.0/PKG-INFO +618 -0
- enpaf-1.0.0/README.md +580 -0
- enpaf-1.0.0/enpaf/__init__.py +11 -0
- enpaf-1.0.0/enpaf/android/__init__.py +1 -0
- enpaf-1.0.0/enpaf/android/deeplinks.py +69 -0
- enpaf-1.0.0/enpaf/android/features.py +72 -0
- enpaf-1.0.0/enpaf/android/permissions.py +98 -0
- enpaf-1.0.0/enpaf/android/runtime.py +109 -0
- enpaf-1.0.0/enpaf/android/webview.py +42 -0
- enpaf-1.0.0/enpaf/builder/__init__.py +1 -0
- enpaf-1.0.0/enpaf/builder/apk_builder.py +124 -0
- enpaf-1.0.0/enpaf/builder/project_generator.py +619 -0
- enpaf-1.0.0/enpaf/cli/__init__.py +1 -0
- enpaf-1.0.0/enpaf/cli/commands/__init__.py +1 -0
- enpaf-1.0.0/enpaf/cli/commands/build.py +360 -0
- enpaf-1.0.0/enpaf/cli/commands/create.py +187 -0
- enpaf-1.0.0/enpaf/cli/commands/doctor.py +176 -0
- enpaf-1.0.0/enpaf/cli/commands/run.py +91 -0
- enpaf-1.0.0/enpaf/cli/main.py +146 -0
- enpaf-1.0.0/enpaf/cli/ui.py +297 -0
- enpaf-1.0.0/enpaf/core/__init__.py +9 -0
- enpaf-1.0.0/enpaf/core/api.py +124 -0
- enpaf-1.0.0/enpaf/core/app.py +293 -0
- enpaf-1.0.0/enpaf/core/bridge.py +146 -0
- enpaf-1.0.0/enpaf/core/config_panel.py +526 -0
- enpaf-1.0.0/enpaf/core/events.py +107 -0
- enpaf-1.0.0/enpaf/core/router.py +133 -0
- enpaf-1.0.0/enpaf/core/server.py +358 -0
- enpaf-1.0.0/enpaf/core/storage.py +254 -0
- enpaf-1.0.0/enpaf/template/app/css/style.css +675 -0
- enpaf-1.0.0/enpaf/template/app/index.html +126 -0
- enpaf-1.0.0/enpaf/template/app/js/app.js +208 -0
- enpaf-1.0.0/enpaf/template/app/pages/about.html +34 -0
- enpaf-1.0.0/enpaf/template/enpaf.json +21 -0
- enpaf-1.0.0/enpaf/template/main.py +104 -0
- enpaf-1.0.0/enpaf.egg-info/PKG-INFO +618 -0
- enpaf-1.0.0/enpaf.egg-info/SOURCES.txt +46 -0
- enpaf-1.0.0/enpaf.egg-info/dependency_links.txt +1 -0
- enpaf-1.0.0/enpaf.egg-info/entry_points.txt +2 -0
- enpaf-1.0.0/enpaf.egg-info/requires.txt +10 -0
- enpaf-1.0.0/enpaf.egg-info/top_level.txt +2 -0
- enpaf-1.0.0/enpaf_bridge/__init__.py +19 -0
- enpaf-1.0.0/enpaf_bridge/enpaf.js +538 -0
- enpaf-1.0.0/pyproject.toml +64 -0
- enpaf-1.0.0/requirements.txt +6 -0
- enpaf-1.0.0/setup.cfg +4 -0
enpaf-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ENPAF Team
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
enpaf-1.0.0/MANIFEST.in
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
include README.md
|
|
2
|
+
include LICENSE
|
|
3
|
+
include requirements.txt
|
|
4
|
+
include pyproject.toml
|
|
5
|
+
|
|
6
|
+
# Project template shipped with the package (used by `paf create`)
|
|
7
|
+
recursive-include enpaf/template *
|
|
8
|
+
|
|
9
|
+
# Client-side JS bridge served in dev and copied into the APK
|
|
10
|
+
recursive-include enpaf_bridge *.js
|
|
11
|
+
|
|
12
|
+
# Keep build artifacts / examples out of the distribution
|
|
13
|
+
prune testapp
|
|
14
|
+
prune dist
|
|
15
|
+
prune build
|
|
16
|
+
prune .enpaf_build
|
|
17
|
+
global-exclude __pycache__
|
|
18
|
+
global-exclude *.py[cod]
|
|
19
|
+
global-exclude *.so
|
enpaf-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,618 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: enpaf
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: ENPAF — Python + Web framework for building Android APK applications
|
|
5
|
+
Author: ENPAF Team
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/enpaf/enpaf
|
|
8
|
+
Project-URL: Documentation, https://enpaf.dev
|
|
9
|
+
Keywords: android,apk,python,webview,framework,mobile
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Environment :: Console
|
|
15
|
+
Classifier: Environment :: Web Environment
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
24
|
+
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
25
|
+
Requires-Python: >=3.9
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
License-File: LICENSE
|
|
28
|
+
Requires-Dist: flask>=3.0.0
|
|
29
|
+
Requires-Dist: flask-socketio>=5.3.0
|
|
30
|
+
Requires-Dist: simple-websocket>=1.0.0
|
|
31
|
+
Requires-Dist: watchdog>=3.0.0
|
|
32
|
+
Requires-Dist: jinja2>=3.1.0
|
|
33
|
+
Requires-Dist: colorama>=0.4.6
|
|
34
|
+
Provides-Extra: dev
|
|
35
|
+
Requires-Dist: build>=1.0.0; extra == "dev"
|
|
36
|
+
Requires-Dist: twine>=5.0.0; extra == "dev"
|
|
37
|
+
Dynamic: license-file
|
|
38
|
+
|
|
39
|
+
# 🚀 ENPAF — Engine for Native Python App Framework
|
|
40
|
+
|
|
41
|
+
**Создавайте Android-приложения на Python + HTML/CSS/JS и собирайте их в APK.**
|
|
42
|
+
|
|
43
|
+
ENPAF — это фреймворк, который позволяет писать мобильные приложения, используя
|
|
44
|
+
привычный веб-стек (HTML/CSS/JS) для интерфейса и **Python** для логики. В режиме
|
|
45
|
+
разработки приложение работает как обычный сайт (Flask + WebSocket + hot-reload), а
|
|
46
|
+
готовый продукт собирается в настоящий **APK** на базе WebView + встроенного Python
|
|
47
|
+
(Chaquopy).
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
┌──────────────────────── Android APK ────────────────────────┐
|
|
51
|
+
│ ┌────────────┐ Bridge (JSON) ┌────────────────────┐ │
|
|
52
|
+
│ │ WebView │ ◄───────────────► │ Python (main.py) │ │
|
|
53
|
+
│ │ HTML/CSS/JS│ │ enpaf core │ │
|
|
54
|
+
│ │ + enpaf.js │ │ ваш код │ │
|
|
55
|
+
│ └────────────┘ └────────────────────┘ │
|
|
56
|
+
└──────────────────────────────────────────────────────────────┘
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## 📑 Содержание
|
|
62
|
+
|
|
63
|
+
- [Возможности](#-возможности)
|
|
64
|
+
- [Установка](#-установка)
|
|
65
|
+
- [Требования](#-требования)
|
|
66
|
+
- [Быстрый старт](#-быстрый-старт)
|
|
67
|
+
- [CLI: команда `paf`](#-cli-команда-paf)
|
|
68
|
+
- [Структура проекта](#-структура-проекта)
|
|
69
|
+
- [Конфигурация `enpaf.json`](#-конфигурация-enpafjson)
|
|
70
|
+
- [Python API](#-python-api)
|
|
71
|
+
- [JavaScript SDK (`enpaf.js`)](#-javascript-sdk-enpafjs)
|
|
72
|
+
- [Панель настроек ⚙](#-панель-настроек-)
|
|
73
|
+
- [Разрешения и фичи устройства](#-разрешения-и-фичи-устройства)
|
|
74
|
+
- [Deep links (диплинки)](#-deep-links-диплинки)
|
|
75
|
+
- [Уведомления и нативные возможности](#-уведомления-и-нативные-возможности)
|
|
76
|
+
- [Сборка APK](#-сборка-apk)
|
|
77
|
+
- [Что можно импортировать](#-что-можно-импортировать)
|
|
78
|
+
- [Решение проблем](#-решение-проблем)
|
|
79
|
+
- [Публикация в PyPI (для мейнтейнеров)](#-публикация-в-pypi-для-мейнтейнеров)
|
|
80
|
+
- [Лицензия](#-лицензия)
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## ✨ Возможности
|
|
85
|
+
|
|
86
|
+
- 🐍 **Python для логики**, HTML/CSS/JS для интерфейса.
|
|
87
|
+
- 🔗 **Двусторонний мост** Python ↔ JavaScript (вызовы и события).
|
|
88
|
+
- 💾 **Встроенное хранилище** — key-value и коллекции на SQLite.
|
|
89
|
+
- ⚡ **Hot-reload** в режиме разработки.
|
|
90
|
+
- ⚙️ **Веб-панель настроек** — иконка, имя, ориентация, цвета, разрешения, фичи и диплинки настраиваются прямо в браузере и пишутся в `enpaf.json`.
|
|
91
|
+
- 📱 **Нативные API** — toast, вибрация, уведомления, буфер обмена, шаринг, ориентация.
|
|
92
|
+
- 🔐 **Разрешения** и **`uses-feature`** (камера, NFC, датчики, Bluetooth, GPS…).
|
|
93
|
+
- 🔗 **Deep links** (кастомные схемы и App Links).
|
|
94
|
+
- 📦 **Сборка в APK/AAB** на Windows/macOS/Linux через Gradle + Chaquopy.
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## 📥 Установка
|
|
99
|
+
|
|
100
|
+
### Из PyPI
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
pip install enpaf
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
После установки доступна команда `paf` и пакет `enpaf` для импорта.
|
|
107
|
+
|
|
108
|
+
### Из исходников (для разработки фреймворка)
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
git clone https://github.com/enpaf/enpaf
|
|
112
|
+
cd enpaf
|
|
113
|
+
pip install -e .
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## 📋 Требования
|
|
119
|
+
|
|
120
|
+
| Что | Зачем | Версия |
|
|
121
|
+
|-----|-------|--------|
|
|
122
|
+
| **Python** | фреймворк и CLI | 3.9+ |
|
|
123
|
+
| **Java JDK** | сборка APK | **17–21** (рекомендуется 17) |
|
|
124
|
+
| **Android SDK** | сборка APK | Android Studio или command-line tools |
|
|
125
|
+
|
|
126
|
+
> Для **разработки** (`paf run`) нужен только Python. JDK и Android SDK нужны
|
|
127
|
+
> только для **сборки APK** (`paf build`). Проверить окружение: `paf doctor`.
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## ⚡ Быстрый старт
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
paf create myapp # создать проект
|
|
135
|
+
cd myapp
|
|
136
|
+
paf run # запустить dev-сервер → http://127.0.0.1:8080
|
|
137
|
+
# ... разрабатываете, правите app/ и main.py, страница перезагружается сама ...
|
|
138
|
+
paf build apk # собрать APK → dist/myapp-1.0.0.apk
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Установить APK на телефон:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
adb install dist/myapp-1.0.0.apk
|
|
145
|
+
# либо просто перекиньте .apk на телефон и откройте
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## 🛠 CLI: команда `paf`
|
|
151
|
+
|
|
152
|
+
| Команда | Описание |
|
|
153
|
+
|---------|----------|
|
|
154
|
+
| `paf create <name>` | Создать новый проект из шаблона |
|
|
155
|
+
| `paf run` | Запустить dev-сервер (Flask + hot-reload) |
|
|
156
|
+
| `paf build apk` | Собрать **debug** APK |
|
|
157
|
+
| `paf build apk --release` | Собрать **release** APK |
|
|
158
|
+
| `paf build aab` | Собрать **release** Android App Bundle (`.aab`) |
|
|
159
|
+
| `paf doctor` | Проверить окружение (Python, JDK, Android SDK) |
|
|
160
|
+
| `paf info` | Показать информацию о текущем проекте |
|
|
161
|
+
|
|
162
|
+
**Флаги `create`:**
|
|
163
|
+
- `--package`, `-p` — Android package id (по умолчанию `com.enpaf.<name>`)
|
|
164
|
+
- `--template`, `-t` — шаблон проекта (по умолчанию `default`)
|
|
165
|
+
|
|
166
|
+
**Флаги `run`:**
|
|
167
|
+
- `--host` (по умолчанию `127.0.0.1`)
|
|
168
|
+
- `--port` (по умолчанию `8080`)
|
|
169
|
+
- `--no-browser` — не открывать браузер автоматически
|
|
170
|
+
- `--debug` — режим отладки
|
|
171
|
+
|
|
172
|
+
**Флаги `build`:**
|
|
173
|
+
- `--release` — релизная сборка
|
|
174
|
+
- `--keystore <path>` — keystore для подписи
|
|
175
|
+
- `--clean` — чистая сборка (удалить кэш сборки)
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## 🏗 Структура проекта
|
|
180
|
+
|
|
181
|
+
```
|
|
182
|
+
myapp/
|
|
183
|
+
├── app/ # Интерфейс (HTML/CSS/JS) → попадёт в assets APK
|
|
184
|
+
│ ├── index.html # Главная страница
|
|
185
|
+
│ ├── css/style.css
|
|
186
|
+
│ ├── js/app.js
|
|
187
|
+
│ ├── pages/ # Доп. страницы
|
|
188
|
+
│ └── img/
|
|
189
|
+
├── main.py # Python-логика (точка входа)
|
|
190
|
+
├── enpaf.json # Конфигурация проекта
|
|
191
|
+
├── icon.png # (опционально) иконка приложения
|
|
192
|
+
├── data/ # Локальная БД (SQLite) — создаётся автоматически
|
|
193
|
+
└── dist/ # Готовые APK после сборки
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
## ⚙️ Конфигурация `enpaf.json`
|
|
199
|
+
|
|
200
|
+
Полный пример со всеми полями:
|
|
201
|
+
|
|
202
|
+
```json
|
|
203
|
+
{
|
|
204
|
+
"name": "My App",
|
|
205
|
+
"package": "com.example.myapp",
|
|
206
|
+
"version": "1.0.0",
|
|
207
|
+
"description": "My ENPAF Application",
|
|
208
|
+
"author": "Developer",
|
|
209
|
+
"orientation": "portrait",
|
|
210
|
+
"icon": "icon.png",
|
|
211
|
+
"permissions": ["INTERNET", "CAMERA", "VIBRATE"],
|
|
212
|
+
"features": [
|
|
213
|
+
{ "key": "CAMERA", "required": true },
|
|
214
|
+
{ "key": "NFC", "required": false }
|
|
215
|
+
],
|
|
216
|
+
"deeplinks": [
|
|
217
|
+
{ "label": "Open profile", "scheme": "myapp", "host": "open",
|
|
218
|
+
"path": "/profile", "pathType": "prefix", "autoVerify": false }
|
|
219
|
+
],
|
|
220
|
+
"python_requirements": ["requests"],
|
|
221
|
+
"min_sdk": 24,
|
|
222
|
+
"target_sdk": 34,
|
|
223
|
+
"theme": {
|
|
224
|
+
"primary_color": "#6C5CE7",
|
|
225
|
+
"status_bar_color": "#5A4BD1"
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
| Поле | Тип | Описание |
|
|
231
|
+
|------|-----|----------|
|
|
232
|
+
| `name` | string | Название приложения (ярлык на устройстве) |
|
|
233
|
+
| `package` | string | Android application id, напр. `com.example.myapp` |
|
|
234
|
+
| `version` | string | Версия (`major.minor.patch`) |
|
|
235
|
+
| `description`, `author` | string | Метаданные |
|
|
236
|
+
| `orientation` | string | `portrait` / `landscape` / `auto` / `sensor` / `unspecified` |
|
|
237
|
+
| `icon` | string | Путь к иконке (PNG/JPG/WebP) относительно проекта |
|
|
238
|
+
| `permissions` | string[] | Список ключей разрешений (см. [таблицу](#разрешения)) |
|
|
239
|
+
| `features` | object[] | `{ "key": "...", "required": true|false }` (`<uses-feature>`) |
|
|
240
|
+
| `deeplinks` | object[] | Диплинки (см. [раздел](#-deep-links-диплинки)) |
|
|
241
|
+
| `python_requirements` | string[] | pip-зависимости, встраиваемые в APK через Chaquopy |
|
|
242
|
+
| `min_sdk` / `target_sdk` | int | Android API levels (по умолчанию 24 / 34) |
|
|
243
|
+
| `theme.primary_color` | string | Основной цвет (HEX) |
|
|
244
|
+
| `theme.status_bar_color` | string | Цвет статус-бара (HEX) |
|
|
245
|
+
| `log_level` | string | Уровень логирования (`INFO`, `DEBUG`, …) |
|
|
246
|
+
|
|
247
|
+
> 💡 Эти поля удобнее всего редактировать через [панель настроек ⚙](#-панель-настроек-),
|
|
248
|
+
> не открывая JSON вручную.
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
## 🐍 Python API
|
|
253
|
+
|
|
254
|
+
### `main.py` — точка входа
|
|
255
|
+
|
|
256
|
+
```python
|
|
257
|
+
from enpaf import EnpafApp
|
|
258
|
+
|
|
259
|
+
app = EnpafApp(__name__)
|
|
260
|
+
|
|
261
|
+
# ─── Маршруты страниц (Jinja2-шаблоны, режим разработки) ───
|
|
262
|
+
@app.route("/")
|
|
263
|
+
def index():
|
|
264
|
+
return app.render("index.html", title=app.name)
|
|
265
|
+
|
|
266
|
+
# ─── Bridge-функции (вызываются из JavaScript) ───
|
|
267
|
+
@app.bridge_handler("get_user")
|
|
268
|
+
def get_user(params):
|
|
269
|
+
user_id = params.get("id")
|
|
270
|
+
return {"id": user_id, "name": "Alex"}
|
|
271
|
+
|
|
272
|
+
# ─── События жизненного цикла ───
|
|
273
|
+
@app.on("app_start")
|
|
274
|
+
def on_start():
|
|
275
|
+
print("Приложение запущено!")
|
|
276
|
+
|
|
277
|
+
if __name__ == "__main__":
|
|
278
|
+
app.run()
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
### Класс `EnpafApp`
|
|
282
|
+
|
|
283
|
+
```python
|
|
284
|
+
EnpafApp(import_name, app_dir="app", config_file="enpaf.json")
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
**Декораторы / методы:**
|
|
288
|
+
|
|
289
|
+
| Метод | Назначение |
|
|
290
|
+
|-------|------------|
|
|
291
|
+
| `@app.route(path, methods=None)` | Зарегистрировать страницу-маршрут |
|
|
292
|
+
| `@app.bridge_handler(name)` / `@app.bridge_func(name)` | Зарегистрировать функцию, вызываемую из JS |
|
|
293
|
+
| `@app.on(event)` | Подписаться на событие |
|
|
294
|
+
| `app.emit(event, data=None)` | Отправить событие (в Python и в JS) |
|
|
295
|
+
| `app.render(template, **context)` | Отрендерить Jinja2-шаблон из `app/` |
|
|
296
|
+
| `app.run(host, port, debug, open_browser)` | Запустить (dev-сервер или Android runtime) |
|
|
297
|
+
|
|
298
|
+
**Свойства / компоненты:**
|
|
299
|
+
|
|
300
|
+
| Свойство | Тип | Описание |
|
|
301
|
+
|----------|-----|----------|
|
|
302
|
+
| `app.config` | dict | Содержимое `enpaf.json` |
|
|
303
|
+
| `app.name` | str | Имя приложения |
|
|
304
|
+
| `app.storage` | `Storage` | Локальное хранилище |
|
|
305
|
+
| `app.events` | `EventEmitter` | Система событий |
|
|
306
|
+
| `app.bridge` | `Bridge` | Мост Python↔JS |
|
|
307
|
+
| `app.api` | `DeviceAPI` | Доступ к функциям устройства |
|
|
308
|
+
| `app.router` | `Router` | Роутер/шаблонизатор |
|
|
309
|
+
|
|
310
|
+
### Хранилище — `app.storage`
|
|
311
|
+
|
|
312
|
+
Key-value:
|
|
313
|
+
|
|
314
|
+
```python
|
|
315
|
+
app.storage.set("theme", "dark") # значение (str/int/float/bool/dict/list)
|
|
316
|
+
theme = app.storage.get("theme", "light") # с дефолтом
|
|
317
|
+
app.storage.delete("theme")
|
|
318
|
+
app.storage.exists("theme") # -> bool
|
|
319
|
+
app.storage.keys("user_%") # LIKE-паттерн
|
|
320
|
+
app.storage.all() # -> dict всех пар
|
|
321
|
+
app.storage.clear()
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
Коллекции (мини документ-стор):
|
|
325
|
+
|
|
326
|
+
```python
|
|
327
|
+
notes = app.storage.collection("notes")
|
|
328
|
+
note_id = notes.add({"text": "Привет"}) # -> int (id)
|
|
329
|
+
notes.all() # -> list[dict] (+ _id, _created_at)
|
|
330
|
+
notes.find({"text": "Привет"}) # -> list[dict]
|
|
331
|
+
notes.find_one({"text": "Привет"}) # -> dict | None
|
|
332
|
+
notes.update(note_id, {"text": "Пока"})
|
|
333
|
+
notes.delete(note_id)
|
|
334
|
+
notes.count() # -> int
|
|
335
|
+
notes.clear()
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
> На Android БД автоматически пишется в записываемый каталог приложения
|
|
339
|
+
> (`getFilesDir()`), а не рядом с исходниками.
|
|
340
|
+
|
|
341
|
+
### События — `app.events`
|
|
342
|
+
|
|
343
|
+
```python
|
|
344
|
+
@app.on("app_start")
|
|
345
|
+
def _(): ...
|
|
346
|
+
|
|
347
|
+
app.events.once("page_load", handler) # сработает один раз
|
|
348
|
+
app.events.off("app_start", handler) # отписаться
|
|
349
|
+
app.events.emit("my_event", payload) # вызвать
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
**Встроенные lifecycle-события:** `app_start`, `app_stop`, `app_pause`,
|
|
353
|
+
`app_resume`, `app_error`, `page_load`, `page_unload`, `bridge_connect`,
|
|
354
|
+
`bridge_disconnect`.
|
|
355
|
+
|
|
356
|
+
### Функции устройства — `app.api` (`DeviceAPI`)
|
|
357
|
+
|
|
358
|
+
```python
|
|
359
|
+
app.api.toast("Сохранено!", duration="short") # "short" | "long"
|
|
360
|
+
app.api.vibrate(200) # мс
|
|
361
|
+
app.api.get_device_info() # -> dict
|
|
362
|
+
app.api.set_status_bar_color("#000000")
|
|
363
|
+
app.api.set_orientation("portrait") # "portrait"|"landscape"|"auto"
|
|
364
|
+
app.api.open_url("https://example.com")
|
|
365
|
+
app.api.clipboard_set("текст")
|
|
366
|
+
app.api.clipboard_get()
|
|
367
|
+
app.api.share("Посмотри!", title="Моё приложение")
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
---
|
|
371
|
+
|
|
372
|
+
## 🌐 JavaScript SDK (`enpaf.js`)
|
|
373
|
+
|
|
374
|
+
Мост `enpaf.js` подключается автоматически: в режиме разработки его внедряет
|
|
375
|
+
сервер, а при сборке APK — билдер вставляет `<script src="js/enpaf.js">` в ваши
|
|
376
|
+
HTML-страницы. Глобальный объект — `window.enpaf`.
|
|
377
|
+
|
|
378
|
+
### Вызовы и события
|
|
379
|
+
|
|
380
|
+
```javascript
|
|
381
|
+
// Вызвать Python-функцию (-> Promise)
|
|
382
|
+
const user = await enpaf.call("get_user", { id: 42 });
|
|
383
|
+
|
|
384
|
+
// События из Python
|
|
385
|
+
enpaf.on("data_updated", (payload) => console.log(payload));
|
|
386
|
+
enpaf.off("data_updated");
|
|
387
|
+
|
|
388
|
+
// Отправить событие в Python
|
|
389
|
+
enpaf.emit("button_clicked", { id: "save" });
|
|
390
|
+
|
|
391
|
+
// Готовность моста
|
|
392
|
+
enpaf.ready(() => console.log("bridge ready"));
|
|
393
|
+
|
|
394
|
+
// Навигация между страницами
|
|
395
|
+
enpaf.navigate("/pages/about.html");
|
|
396
|
+
|
|
397
|
+
enpaf.version; // "1.0.0"
|
|
398
|
+
enpaf.isAndroid; // true в APK, false в браузере
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
### Хранилище из JS
|
|
402
|
+
|
|
403
|
+
```javascript
|
|
404
|
+
await enpaf.storage.set("theme", "dark");
|
|
405
|
+
const theme = await enpaf.storage.get("theme");
|
|
406
|
+
await enpaf.storage.delete("theme");
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
### Функции устройства — `enpaf.device`
|
|
410
|
+
|
|
411
|
+
| Метод | Описание |
|
|
412
|
+
|-------|----------|
|
|
413
|
+
| `enpaf.device.toast(msg, dur)` | Toast-уведомление (`"short"`/`"long"`) |
|
|
414
|
+
| `enpaf.device.vibrate(ms)` | Вибрация |
|
|
415
|
+
| `enpaf.device.notify(title, text, id)` | Системное уведомление |
|
|
416
|
+
| `enpaf.device.share(text, title)` | Системный «Поделиться» |
|
|
417
|
+
| `enpaf.device.setOrientation(mode)` | `"portrait"`/`"landscape"`/`"auto"` |
|
|
418
|
+
| `enpaf.device.clipboard(text)` | Скопировать в буфер обмена |
|
|
419
|
+
| `enpaf.device.openUrl(url)` | Открыть ссылку во внешнем браузере |
|
|
420
|
+
| `enpaf.device.getInfo()` | Информация об окружении (Promise) |
|
|
421
|
+
|
|
422
|
+
В браузере (dev) методы используют веб-аналоги (Web Notifications, `navigator.share`,
|
|
423
|
+
`navigator.clipboard` и т.д.), на Android — нативные вызовы.
|
|
424
|
+
|
|
425
|
+
### Утилиты
|
|
426
|
+
|
|
427
|
+
```javascript
|
|
428
|
+
enpaf.utils.formatDate(Date.now(), "ru-RU");
|
|
429
|
+
enpaf.utils.uid(); // случайный id
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
---
|
|
433
|
+
|
|
434
|
+
## ⚙️ Панель настроек ⚙
|
|
435
|
+
|
|
436
|
+
Запустите `paf run` и откройте **`http://127.0.0.1:8080/enpaf-settings`** (или нажмите
|
|
437
|
+
плавающую кнопку **⚙** в правом нижнем углу страницы). Панель позволяет настроить и
|
|
438
|
+
сохранить в `enpaf.json` без ручного редактирования:
|
|
439
|
+
|
|
440
|
+
- **General** — имя приложения, **иконка** (загрузка с превью), ориентация, основной цвет и цвет статус-бара;
|
|
441
|
+
- **Permissions** — разрешения (`<uses-permission>`);
|
|
442
|
+
- **Hardware features** — фичи устройства (`<uses-feature>`) с флагом «required»;
|
|
443
|
+
- **Deep Links** — диплинки и App Links;
|
|
444
|
+
- **Manifest preview** — живой предпросмотр того, что попадёт в `AndroidManifest.xml`.
|
|
445
|
+
|
|
446
|
+
После «Save» изменения применятся при следующей `paf build`.
|
|
447
|
+
|
|
448
|
+
---
|
|
449
|
+
|
|
450
|
+
## 🔐 Разрешения и фичи устройства
|
|
451
|
+
|
|
452
|
+
### Разрешения
|
|
453
|
+
|
|
454
|
+
Указываются по коротким ключам в `permissions`. Доступные ключи:
|
|
455
|
+
|
|
456
|
+
`INTERNET`, `VIBRATE`, `CAMERA`, `READ_STORAGE`, `WRITE_STORAGE`, `FINE_LOCATION`,
|
|
457
|
+
`COARSE_LOCATION`, `RECORD_AUDIO`, `READ_CONTACTS`, `CALL_PHONE`, `SEND_SMS`,
|
|
458
|
+
`BLUETOOTH`, `BLUETOOTH_ADMIN`, `NFC`, `WAKE_LOCK`, `FOREGROUND_SERVICE`,
|
|
459
|
+
`POST_NOTIFICATIONS`.
|
|
460
|
+
|
|
461
|
+
Можно указать и полное имя, напр. `android.permission.CAMERA`.
|
|
462
|
+
|
|
463
|
+
### Фичи (`<uses-feature>`)
|
|
464
|
+
|
|
465
|
+
Формат: `{ "key": "<KEY>", "required": true|false }`. Доступные ключи:
|
|
466
|
+
|
|
467
|
+
`CAMERA`, `CAMERA_FRONT`, `CAMERA_AUTOFOCUS`, `NFC`, `BLUETOOTH`, `BLUETOOTH_LE`,
|
|
468
|
+
`GPS`, `LOCATION`, `MICROPHONE`, `WIFI`, `TELEPHONY`, `TOUCHSCREEN`, `FINGERPRINT`,
|
|
469
|
+
`ACCELEROMETER`, `GYROSCOPE`, `COMPASS`, `PROXIMITY`, `LIGHT`, `BAROMETER`,
|
|
470
|
+
`STEP_COUNTER`, `HEART_RATE`.
|
|
471
|
+
|
|
472
|
+
> `required: false` оставляет приложение устанавливаемым на устройствах без
|
|
473
|
+
> соответствующего железа.
|
|
474
|
+
|
|
475
|
+
---
|
|
476
|
+
|
|
477
|
+
## 🔗 Deep links (диплинки)
|
|
478
|
+
|
|
479
|
+
Каждый диплинк превращается в `<intent-filter>` на главной активности.
|
|
480
|
+
|
|
481
|
+
```json
|
|
482
|
+
"deeplinks": [
|
|
483
|
+
{ "label": "Профиль", "scheme": "myapp", "host": "open",
|
|
484
|
+
"path": "/profile", "pathType": "prefix", "autoVerify": false }
|
|
485
|
+
]
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
| Поле | Описание |
|
|
489
|
+
|------|----------|
|
|
490
|
+
| `scheme` | Обязательно. Напр. `myapp` или `https` |
|
|
491
|
+
| `host` | Опционально. Напр. `example.com` |
|
|
492
|
+
| `path` | Опционально. Напр. `/profile` |
|
|
493
|
+
| `pathType` | `path` (точно) / `prefix` / `pattern` |
|
|
494
|
+
| `autoVerify` | `true` для App Links (проверяемые https-ссылки) |
|
|
495
|
+
| `label` | Только для UI-панели |
|
|
496
|
+
|
|
497
|
+
Проверить диплинк на устройстве:
|
|
498
|
+
|
|
499
|
+
```bash
|
|
500
|
+
adb shell am start -a android.intent.action.VIEW -d "myapp://open/profile"
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
---
|
|
504
|
+
|
|
505
|
+
## 🔔 Уведомления и нативные возможности
|
|
506
|
+
|
|
507
|
+
Из JavaScript:
|
|
508
|
+
|
|
509
|
+
```javascript
|
|
510
|
+
enpaf.device.notify("Заголовок", "Текст уведомления", 1);
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
На Android уведомления используют канал по умолчанию; на Android 13+ приложение
|
|
514
|
+
запрашивает разрешение `POST_NOTIFICATIONS` (добавьте его в `permissions`).
|
|
515
|
+
|
|
516
|
+
Доступные нативные методы моста (вызываются через `enpaf.device.*`): `toast`,
|
|
517
|
+
`vibrate`, `notify`, `share`, `setOrientation`, `clipboard`, `openUrl`.
|
|
518
|
+
|
|
519
|
+
---
|
|
520
|
+
|
|
521
|
+
## 📦 Сборка APK
|
|
522
|
+
|
|
523
|
+
```bash
|
|
524
|
+
paf build apk # debug
|
|
525
|
+
paf build apk --release # release
|
|
526
|
+
paf build aab # release bundle (.aab)
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
Что происходит:
|
|
530
|
+
|
|
531
|
+
1. Проверяется окружение (Python/JDK/Android SDK).
|
|
532
|
+
2. Подбирается совместимая **JDK 17–21** (учитывается `JAVA_HOME`; иначе ищется в стандартных местах, включая JBR из Android Studio).
|
|
533
|
+
3. Генерируется Gradle-проект (Chaquopy), скачивается официальный Gradle wrapper.
|
|
534
|
+
4. Gradle собирает APK; результат копируется в `dist/<name>-<version>.apk`.
|
|
535
|
+
|
|
536
|
+
**Первая сборка долгая** — Gradle докачивает Android platform/build-tools и **NDK
|
|
537
|
+
(~1 ГБ)** для Chaquopy. Дальнейшие сборки быстрее (всё кэшируется в `~/.gradle` и
|
|
538
|
+
Android SDK).
|
|
539
|
+
|
|
540
|
+
### OneDrive / облачные папки
|
|
541
|
+
|
|
542
|
+
Если проект лежит в OneDrive (или другой синхронизируемой папке), ENPAF
|
|
543
|
+
**автоматически** выносит каталог сборки в `%LOCALAPPDATA%\enpaf\builds\…`, потому что
|
|
544
|
+
синхронизация ломает удаление файлов Gradle. Путь можно переопределить переменной
|
|
545
|
+
окружения `ENPAF_BUILD_DIR`. Итоговый APK всё равно копируется в `dist/`.
|
|
546
|
+
|
|
547
|
+
---
|
|
548
|
+
|
|
549
|
+
## 📥 Что можно импортировать
|
|
550
|
+
|
|
551
|
+
**Основное (рекомендуется):**
|
|
552
|
+
|
|
553
|
+
```python
|
|
554
|
+
from enpaf import EnpafApp, __version__
|
|
555
|
+
```
|
|
556
|
+
|
|
557
|
+
**Продвинутое** (обычно используется через `app.*`, но доступно напрямую):
|
|
558
|
+
|
|
559
|
+
```python
|
|
560
|
+
from enpaf.core.storage import Storage, Collection
|
|
561
|
+
from enpaf.core.events import EventEmitter
|
|
562
|
+
from enpaf.core.bridge import Bridge
|
|
563
|
+
from enpaf.core.router import Router
|
|
564
|
+
from enpaf.core.api import DeviceAPI
|
|
565
|
+
|
|
566
|
+
# Справочники для манифеста / панели настроек
|
|
567
|
+
from enpaf.android.permissions import PERMISSIONS, get_permission_catalog
|
|
568
|
+
from enpaf.android.features import FEATURES, get_feature_catalog
|
|
569
|
+
from enpaf.android.deeplinks import get_deeplink_xml
|
|
570
|
+
|
|
571
|
+
# Программная сборка APK
|
|
572
|
+
from enpaf.builder.apk_builder import APKBuilder
|
|
573
|
+
|
|
574
|
+
# Точка входа CLI
|
|
575
|
+
from enpaf.cli.main import main
|
|
576
|
+
```
|
|
577
|
+
|
|
578
|
+
Клиентский SDK для подключения вручную (если не используете авто-инъекцию):
|
|
579
|
+
|
|
580
|
+
```html
|
|
581
|
+
<script src="js/enpaf.js"></script>
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
---
|
|
585
|
+
|
|
586
|
+
## 🩺 Решение проблем
|
|
587
|
+
|
|
588
|
+
| Симптом | Причина и решение |
|
|
589
|
+
|---------|-------------------|
|
|
590
|
+
| **Приложение сразу закрывается** | Пересоберите APK — фиксы применяются только в новой сборке. Если повторяется — снимите лог: `adb logcat` (теги `AndroidRuntime`, `python.stderr`, `chaquopy`). |
|
|
591
|
+
| **`enpaf is not defined`** | Мост не подключён. Сборка вставляет `js/enpaf.js` автоматически; убедитесь, что собираете свежую версию. |
|
|
592
|
+
| **Синий/неожиданный цвет статус-бара** | Это `theme.status_bar_color`. Поменяйте его в панели ⚙ → General или в `enpaf.json`. |
|
|
593
|
+
| **`Unable to delete directory … python\sources`** | OneDrive блокирует файлы. ENPAF собирает вне OneDrive автоматически; при желании задайте `ENPAF_BUILD_DIR`. |
|
|
594
|
+
| **`Incompatible Java version`** | Нужна JDK 17–21. Установите JDK 17 и задайте `JAVA_HOME`, либо дайте ENPAF найти её автоматически. |
|
|
595
|
+
| **`'""' is not recognized` при Gradle** | Старый сломанный wrapper. Удалите каталог сборки и соберите заново (`paf build apk --clean`). |
|
|
596
|
+
|
|
597
|
+
Полная диагностика окружения: `paf doctor`.
|
|
598
|
+
|
|
599
|
+
---
|
|
600
|
+
|
|
601
|
+
## 📤 Публикация в PyPI (для мейнтейнеров)
|
|
602
|
+
|
|
603
|
+
Пакет уже подготовлен (`pyproject.toml`, `MANIFEST.in`). Подробная пошаговая
|
|
604
|
+
инструкция — в [PUBLISHING.md](PUBLISHING.md). Кратко:
|
|
605
|
+
|
|
606
|
+
```bash
|
|
607
|
+
pip install build twine
|
|
608
|
+
python -m build # создаст dist/*.whl и dist/*.tar.gz
|
|
609
|
+
twine check dist/*
|
|
610
|
+
twine upload --repository testpypi dist/* # сначала на TestPyPI
|
|
611
|
+
twine upload dist/* # затем на PyPI
|
|
612
|
+
```
|
|
613
|
+
|
|
614
|
+
---
|
|
615
|
+
|
|
616
|
+
## 📄 Лицензия
|
|
617
|
+
|
|
618
|
+
MIT License — см. [LICENSE](LICENSE).
|