PyMobileScript Documentation
Build native mobile apps using Python, with high performance and a seamless developer experience.
PyMobileScript is a revolutionary framework that allows Python developers to build native mobile applications for iOS and Android using pure Python code. By leveraging advanced compilation techniques, PyMobileScript translates your Python code directly to native Swift and Kotlin, resulting in high-performance applications with native look and feel.
Key Features
- Pure Python Development: Write your entire application in Python without learning Swift, Kotlin, or JavaScript
- Native Performance: Direct compilation to native code with no interpretation or bridges
- Full Access to Native APIs: Use platform-specific features without writing platform-specific code
- Rapid Development: Hot reload, intelligent debugging, and comprehensive error messages
- Python Ecosystem Integration: Use your favorite Python libraries directly in your mobile apps
Installation
PyMobileScript requires Python 3.8 or higher and can be installed using pip.
System Requirements
- Python 3.8+
- macOS, Windows 10+, or Linux
- For iOS development: macOS with Xcode 13+
- For Android development: Android SDK 30+
- Minimum 8GB RAM recommended
Install PyMobileScript
Install the PyMobileScript framework using pip:
pip install pymobilescript
Verify the installation:
pymobilescript --version
Setting Up Development Environment
Install the CLI tools for creating and managing projects:
pip install pymobilescript-cli
Platform-Specific Setup
For macOS, you'll need to install Xcode for iOS development:
- Install Xcode from the Mac App Store
- Install the Xcode Command Line Tools:
xcode-select --install
- Run the PyMobileScript environment setup:
pymobilescript setup ios
For Android development:
- Install Android Studio
- Install the Android SDK through Android Studio
- Run the PyMobileScript environment setup:
pymobilescript setup android
IDE Integration
PyMobileScript works with any Python IDE, but we recommend using VSCode with our official extension for the best development experience.
- Install Visual Studio Code
- Install the Python extension
- Install the PyMobileScript extension from the marketplace
Quick Start
Let's create your first PyMobileScript application.
Create a New Project
Use the CLI to create a new project with a starter template:
pymobilescript create myapp
This will create a new directory called myapp
with a basic project structure.
Project Structure
Your new project will have the following structure:
myapp/ ├── pyproject.toml # Project configuration ├── README.md # Project documentation ├── app/ │ ├── __init__.py │ ├── main.py # Entry point │ ├── views/ # UI views │ │ ├── __init__.py │ │ ├── home.py │ │ └── settings.py │ ├── components/ # Reusable components │ │ ├── __init__.py │ │ └── button.py │ ├── resources/ # Images, fonts, etc. │ │ ├── images/ │ │ └── fonts/ │ └── utils/ # Utility functions │ └── __init__.py ├── tests/ # Unit tests │ └── __init__.py └── .pymobilescriptrc # Framework configuration
Run Your App
Navigate to your project directory and start the development server:
cd myapp\npymobilescript dev
This will start the development server and launch your app in the simulator/emulator.
To run specifically on iOS:
pymobilescript dev --platform ios
Your First App
Let's look at the default main.py
file created by the template:
import pymobilescript as pms
from pymobilescript.ui import *
from app.views.home import HomeView
class MyApp(pms.App):
def __init__(self):
super().__init__()
self.title = "My First App"
def view(self):
return HomeView()
if __name__ == "__main__":
app = MyApp()
app.run()
Now, let's look at the home.py
file to see the UI definition:
import pymobilescript as pms
from pymobilescript.ui import *
class HomeView(pms.View):
def __init__(self):
super().__init__()
self.count = 0
def increment(self):
self.count += 1
self.update()
def render(self):
return Container(
style={"padding": 20, "alignItems": "center", "justifyContent": "center"},
children=[
Text(
"Welcome to PyMobileScript!",
style={"fontSize": 24, "fontWeight": "bold", "marginBottom": 20}
),
Text(
f"You clicked {self.count} times",
style={"marginBottom": 20}
),
Button(
text="Increment",
on_press=self.increment,
style={"backgroundColor": "#4299e1", "color": "white", "padding": 10, "borderRadius": 5}
)
]
)
This creates a simple counter app with a button that increments the count when pressed.
Making Changes
Let's modify the home view to add some more UI elements:
import pymobilescript as pms
from pymobilescript.ui import *
class HomeView(pms.View):
def __init__(self):
super().__init__()
self.count = 0
self.name = ""
def increment(self):
self.count += 1
self.update()
def on_name_change(self, text):
self.name = text
self.update()
def render(self):
return Container(
style={"padding": 20, "alignItems": "center", "justifyContent": "center"},
children=[
Text(
"Welcome to PyMobileScript!",
style={"fontSize": 24, "fontWeight": "bold", "marginBottom": 20}
),
Input(
placeholder="Enter your name",
value=self.name,
on_change=self.on_name_change,
style={"width": "100%", "marginBottom": 20, "padding": 10, "borderWidth": 1, "borderColor": "#e2e8f0", "borderRadius": 5}
),
Text(
f"Hello, {self.name or 'Friend'}!" if self.name else "Please enter your name above",
style={"marginBottom": 20}
),
Text(
f"You clicked {self.count} times",
style={"marginBottom": 20}
),
Button(
text="Increment",
on_press=self.increment,
style={"backgroundColor": "#4299e1", "color": "white", "padding": 10, "borderRadius": 5}
)
]
)
With these changes, the app now includes a text input field where the user can enter their name, and the UI will update to display a greeting.
Project Structure
Understanding the PyMobileScript project structure is essential for organizing your code effectively.
Core Components
- pyproject.toml: The main configuration file for your project. It contains metadata, dependencies, and build settings.
- app/main.py: The entry point of your application. It defines the main App class and initializes the application.
- app/views/: Contains your application's screens or pages. Each view represents a different screen in your app.
- app/components/: Contains reusable UI components that can be shared across multiple views.
- app/resources/: Contains static resources like images, fonts, and other assets.
- app/utils/: Contains utility functions and helper classes that can be used throughout your application.
- .pymobilescriptrc: Framework-specific configuration file. It contains settings for the build process, plugins, and other framework-specific options.
Configuration Files
The pyproject.toml
file is the main configuration file for your project. Here's an example of a basic configuration:
[project]
name = "my-mobile-app"
version = "0.1.0"
description = "My first PyMobileScript app"
authors = [
{name = "Your Name", email = "your.email@example.com"}
]
requires-python = ">=3.8"
[build-system]
requires = ["pymobilescript-build>=1.0.0"]
build-backend = "pymobilescript.build"
[tool.pymobilescript]
app_name = "My Mobile App"
bundle_id = "com.example.mymobileapp"
version_code = 1
min_sdk_version = 21
target_sdk_version = 31
[tool.pymobilescript.ios]
deployment_target = "14.0"
team_id = "XXXXXXXXXX" # Your Apple Developer Team ID
[tool.pymobilescript.android]
compile_sdk_version = 31
The .pymobilescriptrc
file contains framework-specific configuration options:
{
"plugins": [
"pymobilescript-camera",
"pymobilescript-location"
],
"fonts": [
{
"name": "Roboto",
"assets": [
"app/resources/fonts/Roboto-Regular.ttf",
"app/resources/fonts/Roboto-Bold.ttf",
"app/resources/fonts/Roboto-Italic.ttf"
]
}
],
"environment": {
"development": {
"api_url": "https://api.example.com/dev"
},
"production": {
"api_url": "https://api.example.com/prod"
}
}
}
Recommended Project Organization
As your project grows, we recommend organizing your code according to the following structure:
myapp/ ├── pyproject.toml ├── README.md ├── app/ │ ├── main.py │ ├── views/ │ │ ├── __init__.py │ │ ├── auth/ # Authentication-related views │ │ │ ├── __init__.py │ │ │ ├── login.py │ │ │ └── register.py │ │ ├── main/ # Main app views │ │ │ ├── __init__.py │ │ │ ├── home.py │ │ │ ├── profile.py │ │ │ └── settings.py │ │ └── common/ # Shared views │ │ ├── __init__.py │ │ ├── about.py │ │ └── error.py │ ├── components/ │ │ ├── __init__.py │ │ ├── buttons.py │ │ ├── cards.py │ │ ├── forms.py │ │ └── navigation.py │ ├── models/ # Data models │ │ ├── __init__.py │ │ ├── user.py │ │ └── item.py │ ├── services/ # API and other services │ │ ├── __init__.py │ │ ├── api.py │ │ └── auth.py │ ├── resources/ │ │ ├── images/ │ │ └── fonts/ │ ├── utils/ │ │ ├── __init__.py │ │ ├── validation.py │ │ └── formatting.py │ ├── config.py # App configuration │ └── themes.py # UI themes ├── tests/ │ ├── __init__.py │ ├── test_views.py │ └── test_models.py └── .pymobilescriptrc
Components
Components are the building blocks of PyMobileScript applications. They encapsulate UI elements and logic that can be reused throughout your application.
Built-in Components
PyMobileScript provides a rich set of built-in components that map to native UI elements on iOS and Android.
Text
Displays text with customizable styling
Button
A pressable button with customizable appearance
Input
Text input field for user data entry
Image
Displays local or remote images
Container
Basic layout component for grouping other components
ScrollView
Container that allows scrolling its contents
ListView
Efficiently displays scrollable lists of items
Stack
Layout component that stacks children vertically or horizontally
Grid
Arranges items in a grid layout
Switch
Toggle switch for boolean values
Checkbox
Checkbox for selecting multiple options
RadioButton
Radio button for selecting a single option from many
Slider
Slider for selecting a value from a range
Progress
Displays progress of an operation
Modal
Displays content in a modal window
Tabs
Tabbed navigation component
Creating Custom Components
You can create your own custom components by extending the pms.Component
class.
import pymobilescript as pms
from pymobilescript.ui import *
class CustomButton(pms.Component):
def __init__(self, text, on_press=None, variant="primary"):
super().__init__()
self.text = text
self.on_press = on_press
self.variant = variant
def render(self):
# Define styles based on variant
if self.variant == "primary":
style = {
"backgroundColor": "#4299e1",
"color": "white",
"padding": 12,
"borderRadius": 8,
"fontWeight": "bold"
}
elif self.variant == "secondary":
style = {
"backgroundColor": "#a0aec0",
"color": "white",
"padding": 12,
"borderRadius": 8,
"fontWeight": "bold"
}
else: # outline
style = {
"backgroundColor": "transparent",
"color": "#4299e1",
"padding": 12,
"borderRadius": 8,
"fontWeight": "bold",
"borderWidth": 2,
"borderColor": "#4299e1"
}
return Button(
text=self.text,
on_press=self.on_press,
style=style
)
Using the custom component:
from app.components.custom_button import CustomButton
def render(self):
return Container(
children=[
CustomButton(
text="Primary Button",
on_press=self.handle_press,
variant="primary"
),
CustomButton(
text="Secondary Button",
on_press=self.handle_press,
variant="secondary"
),
CustomButton(
text="Outline Button",
on_press=self.handle_press,
variant="outline"
)
]
)
Component Lifecycle
PyMobileScript components have a lifecycle that you can hook into to perform actions at different stages.
import pymobilescript as pms
from pymobilescript.ui import *
class LifecycleComponent(pms.Component):
def __init__(self):
super().__init__()
self.data = None
def mount(self):
# Called when the component is first mounted
print("Component mounted")
# Perform initialization, API calls, etc.
self.load_data()
def unmount(self):
# Called when the component is removed from the UI
print("Component unmounted")
# Perform cleanup, unsubscribe from events, etc.
def update(self):
# Called when the component's state changes
print("Component updated")
super().update() # Don't forget to call the parent method
def should_update(self, next_props, next_state):
# Return True if the component should re-render
# This is an optimization to prevent unnecessary renders
return True
async def load_data(self):
# Async method to fetch data
self.data = await api.fetch_data()
self.update()
def render(self):
if self.data is None:
return Text("Loading...")
return Container(
children=[
Text(f"Data: {self.data}")
]
)
Component Composition
Component composition is a powerful pattern in PyMobileScript. You can combine smaller components to build more complex UIs.
import pymobilescript as pms
from pymobilescript.ui import *
from app.components.custom_button import CustomButton
from app.components.header import Header
from app.components.card import Card
class ProfileView(pms.View):
def __init__(self, user_id):
super().__init__()
self.user_id = user_id
self.user = None
def mount(self):
self.load_user()
async def load_user(self):
self.user = await api.get_user(self.user_id)
self.update()
def render(self):
if self.user is None:
return Container(
style={"alignItems": "center", "justifyContent": "center", "flex": 1},
children=[
Text("Loading user profile...")
]
)
return Container(
children=[
Header(title="User Profile"),
Card(
children=[
Image(
source=self.user.avatar_url,
style={"width": 100, "height": 100, "borderRadius": 50, "alignSelf": "center"}
),
Text(
self.user.name,
style={"fontSize": 24, "fontWeight": "bold", "textAlign": "center", "marginTop": 10}
),
Text(
self.user.email,
style={"textAlign": "center", "color": "#666"}
)
]
),
CustomButton(
text="Edit Profile",
on_press=self.edit_profile,
variant="primary"
),
CustomButton(
text="Logout",
on_press=self.logout,
variant="outline"
)
]
)
def edit_profile(self):
# Navigate to edit profile screen
self.navigate("edit_profile", {"user_id": self.user_id})
def logout(self):
# Handle logout
api.logout()
self.navigate("login")
Building Your App
When you're ready to distribute your app, you'll need to build it for your target platforms. PyMobileScript simplifies this process with a unified build system.
Building for Development
During development, PyMobileScript uses a development build that includes debug information and tools to help you identify and fix issues.
pymobilescript build --dev
This will create a development build for both iOS and Android.
Building for Production
When you're ready to release your app, you'll need to create a production build. This build is optimized for performance and size.
pymobilescript build --production
This will create a production build for both iOS and Android. The output will be located in the build/
directory.
Platform-Specific Builds
You can also build for a specific platform:
pymobilescript build --platform ios --production
This will create an iOS app bundle (.ipa
file) in the build/ios/
directory.
Build Configuration
You can customize the build process by modifying the build configuration in your pyproject.toml
file:
[tool.pymobilescript.build]
optimization_level = "high" # Can be "none", "low", "medium", or "high"
include_source_maps = false # Whether to include source maps for debugging
asset_compression = true # Whether to compress assets
bundle_identifier = "com.example.myapp"
version = "1.0.0"
build_number = "1"
[tool.pymobilescript.build.ios]
team_id = "XXXXXXXXXX"
provisioning_profile = "path/to/profile.mobileprovision"
code_sign_identity = "iPhone Distribution"
export_method = "app-store" # Can be "app-store", "ad-hoc", "enterprise", or "development"
[tool.pymobilescript.build.android]
keystore = "path/to/keystore.jks"
keystore_password = "your-keystore-password"
key_alias = "your-key-alias"
key_password = "your-key-password"
build_type = "aab" # Can be "apk" or "aab" (Android App Bundle)
Environment-Specific Builds
You can create builds for different environments (e.g., staging, production) by specifying the environment name:
pymobilescript build --env staging
This will use the configuration specified in the environment.staging
section of your .pymobilescriptrc
file.
{
"environment": {
"development": {
"api_url": "https://api.example.com/dev",
"logging_level": "debug"
},
"staging": {
"api_url": "https://api.example.com/staging",
"logging_level": "info"
},
"production": {
"api_url": "https://api.example.com/prod",
"logging_level": "error"
}
}
}
You can access these environment variables in your code:
import pymobilescript as pms
# Access environment variables
api_url = pms.env.get("api_url")
logging_level = pms.env.get("logging_level")
Custom Build Scripts
For more complex build requirements, you can create custom build scripts that run before or after the main build process:
# build_scripts.py
import subprocess
import os
import json
def pre_build(context):
"""Runs before the build process starts."""
print("Running pre-build script...")
# Generate build-specific files
with open("app/build_config.py", "w") as f:
f.write(f"BUILD_NUMBER = '{context['build_number']}'
")
f.write(f"BUILD_ENV = '{context['environment']}'
")
f.write(f"BUILD_DATE = '{context['date']}'
")
def post_build(context):
"""Runs after the build process completes."""
print("Running post-build script...")
# Notify team about new build
build_info = {
"version": context["version"],
"build_number": context["build_number"],
"environment": context["environment"],
"date": context["date"],
"platforms": context["platforms"]
}
with open("build/build_info.json", "w") as f:
json.dump(build_info, f, indent=2)
# Run additional optimization or verification
if "android" in context["platforms"]:
apk_path = os.path.join("build", "android", f"{context['name']}.apk")
subprocess.run(["zipalign", "-v", "4", apk_path, f"{apk_path}.aligned"])
os.rename(f"{apk_path}.aligned", apk_path)
Reference these scripts in your pyproject.toml
:
[tool.pymobilescript.build]
pre_build_script = "build_scripts.pre_build"
post_build_script = "build_scripts.post_build"
iOS Deployment
Deploying your PyMobileScript app to iOS devices and the App Store involves several steps.
Prerequisites
- An Apple Developer account ($99/year)
- Xcode installed on your Mac
- App Store Connect setup for your app
- Certificates and provisioning profiles
Setup for iOS Deployment
Before you can deploy your app, you need to set up your Apple Developer account and create the necessary certificates and provisioning profiles.
The PyMobileScript CLI can help automate this process:
pymobilescript setup ios-deployment
This interactive command will guide you through the process of setting up your iOS deployment credentials.
Deploying to TestFlight
TestFlight allows you to distribute beta versions of your app to testers before releasing it to the App Store.
pymobilescript deploy ios --beta
This will build your app, create an iOS app bundle, and upload it to TestFlight. You can then invite testers through App Store Connect.
App Store Submission
When you're ready to submit your app to the App Store, you can use the deployment command:
pymobilescript deploy ios --release
This will build your app, create an iOS app bundle, and upload it to App Store Connect. You'll need to complete the submission process through the App Store Connect website, including:
- App information and metadata
- Screenshots and app preview videos
- Privacy policy
- App Review information
- Version release information
Advanced iOS Deployment
For more advanced deployment scenarios, you can customize the deployment process with additional options:
pymobilescript deploy ios --release --skip-build --ipa-path ./build/ios/MyApp.ipa --wait-for-processing
This command will:
- Skip the build process (useful if you've already built the app)
- Use a specific .ipa file instead of building a new one
- Wait for App Store Connect to finish processing the build before exiting
iOS Deployment Configuration
You can configure iOS deployment settings in your pyproject.toml
file:
[tool.pymobilescript.deploy.ios]
team_id = "XXXXXXXXXX"
app_store_connect_api_key_id = "XXXXXXXXXX"
app_store_connect_api_issuer_id = "XXXXXXXXXX"
app_store_connect_api_key_path = "path/to/api_key.p8"
app_specific_password = "xxxx-xxxx-xxxx-xxxx" # For Apple ID authentication
skip_build_validation = false
skip_app_store_validation = false
submit_for_review = false # Whether to automatically submit for review