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.
Files changed (48) hide show
  1. enpaf-1.0.0/LICENSE +21 -0
  2. enpaf-1.0.0/MANIFEST.in +19 -0
  3. enpaf-1.0.0/PKG-INFO +618 -0
  4. enpaf-1.0.0/README.md +580 -0
  5. enpaf-1.0.0/enpaf/__init__.py +11 -0
  6. enpaf-1.0.0/enpaf/android/__init__.py +1 -0
  7. enpaf-1.0.0/enpaf/android/deeplinks.py +69 -0
  8. enpaf-1.0.0/enpaf/android/features.py +72 -0
  9. enpaf-1.0.0/enpaf/android/permissions.py +98 -0
  10. enpaf-1.0.0/enpaf/android/runtime.py +109 -0
  11. enpaf-1.0.0/enpaf/android/webview.py +42 -0
  12. enpaf-1.0.0/enpaf/builder/__init__.py +1 -0
  13. enpaf-1.0.0/enpaf/builder/apk_builder.py +124 -0
  14. enpaf-1.0.0/enpaf/builder/project_generator.py +619 -0
  15. enpaf-1.0.0/enpaf/cli/__init__.py +1 -0
  16. enpaf-1.0.0/enpaf/cli/commands/__init__.py +1 -0
  17. enpaf-1.0.0/enpaf/cli/commands/build.py +360 -0
  18. enpaf-1.0.0/enpaf/cli/commands/create.py +187 -0
  19. enpaf-1.0.0/enpaf/cli/commands/doctor.py +176 -0
  20. enpaf-1.0.0/enpaf/cli/commands/run.py +91 -0
  21. enpaf-1.0.0/enpaf/cli/main.py +146 -0
  22. enpaf-1.0.0/enpaf/cli/ui.py +297 -0
  23. enpaf-1.0.0/enpaf/core/__init__.py +9 -0
  24. enpaf-1.0.0/enpaf/core/api.py +124 -0
  25. enpaf-1.0.0/enpaf/core/app.py +293 -0
  26. enpaf-1.0.0/enpaf/core/bridge.py +146 -0
  27. enpaf-1.0.0/enpaf/core/config_panel.py +526 -0
  28. enpaf-1.0.0/enpaf/core/events.py +107 -0
  29. enpaf-1.0.0/enpaf/core/router.py +133 -0
  30. enpaf-1.0.0/enpaf/core/server.py +358 -0
  31. enpaf-1.0.0/enpaf/core/storage.py +254 -0
  32. enpaf-1.0.0/enpaf/template/app/css/style.css +675 -0
  33. enpaf-1.0.0/enpaf/template/app/index.html +126 -0
  34. enpaf-1.0.0/enpaf/template/app/js/app.js +208 -0
  35. enpaf-1.0.0/enpaf/template/app/pages/about.html +34 -0
  36. enpaf-1.0.0/enpaf/template/enpaf.json +21 -0
  37. enpaf-1.0.0/enpaf/template/main.py +104 -0
  38. enpaf-1.0.0/enpaf.egg-info/PKG-INFO +618 -0
  39. enpaf-1.0.0/enpaf.egg-info/SOURCES.txt +46 -0
  40. enpaf-1.0.0/enpaf.egg-info/dependency_links.txt +1 -0
  41. enpaf-1.0.0/enpaf.egg-info/entry_points.txt +2 -0
  42. enpaf-1.0.0/enpaf.egg-info/requires.txt +10 -0
  43. enpaf-1.0.0/enpaf.egg-info/top_level.txt +2 -0
  44. enpaf-1.0.0/enpaf_bridge/__init__.py +19 -0
  45. enpaf-1.0.0/enpaf_bridge/enpaf.js +538 -0
  46. enpaf-1.0.0/pyproject.toml +64 -0
  47. enpaf-1.0.0/requirements.txt +6 -0
  48. 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.
@@ -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).