397 lines
7.5 KiB
Markdown
397 lines
7.5 KiB
Markdown
# Permissions Guide
|
|
|
|
Mosis apps run in a secure sandbox with limited access to device features. To access sensitive capabilities, apps must declare permissions in their manifest.
|
|
|
|
## Why Permissions?
|
|
|
|
Permissions protect user privacy and security by:
|
|
|
|
1. **Informing users** what an app can access before installation
|
|
2. **Limiting damage** if an app misbehaves
|
|
3. **Maintaining trust** in the Mosis ecosystem
|
|
|
|
## Declaring Permissions
|
|
|
|
Add permissions to your `manifest.json`:
|
|
|
|
```json
|
|
{
|
|
"id": "com.example.myapp",
|
|
"name": "My App",
|
|
"permissions": [
|
|
"storage",
|
|
"network"
|
|
]
|
|
}
|
|
```
|
|
|
|
Only request permissions your app actually needs. Users are more likely to trust apps with fewer permissions.
|
|
|
|
## Available Permissions
|
|
|
|
### storage
|
|
|
|
**Description:** Persist data locally between app sessions.
|
|
|
|
**Use cases:**
|
|
- Save user preferences
|
|
- Cache data for offline use
|
|
- Store app state
|
|
|
|
**API access:**
|
|
```lua
|
|
storage.set("key", value)
|
|
storage.get("key")
|
|
storage.remove("key")
|
|
storage.clear()
|
|
```
|
|
|
|
**Note:** All apps have access to in-memory storage during a session. The `storage` permission enables persistence across sessions.
|
|
|
|
---
|
|
|
|
### network
|
|
|
|
**Description:** Make HTTP/HTTPS requests to external servers.
|
|
|
|
**Use cases:**
|
|
- Fetch data from APIs
|
|
- Submit form data
|
|
- Load remote content
|
|
|
|
**API access:**
|
|
```lua
|
|
http.get(url, callback)
|
|
http.post(url, options, callback)
|
|
http.request(options, callback)
|
|
```
|
|
|
|
**Restrictions:**
|
|
- HTTPS only (HTTP blocked for security)
|
|
- Cannot access localhost or internal IPs
|
|
- Subject to CORS policies
|
|
|
|
---
|
|
|
|
### clipboard
|
|
|
|
**Description:** Read from and write to the system clipboard.
|
|
|
|
**Use cases:**
|
|
- Copy text or data
|
|
- Paste user content
|
|
- Share functionality
|
|
|
|
**API access:**
|
|
```lua
|
|
clipboard.write(text)
|
|
clipboard.read(callback)
|
|
```
|
|
|
|
---
|
|
|
|
### notifications
|
|
|
|
**Description:** Display system notifications to the user.
|
|
|
|
**Use cases:**
|
|
- Reminders
|
|
- Alerts
|
|
- Background updates
|
|
|
|
**API access:**
|
|
```lua
|
|
notifications.show({
|
|
title = "Reminder",
|
|
body = "Your timer is done!",
|
|
icon = "icons/alarm.png"
|
|
})
|
|
```
|
|
|
|
**Restrictions:**
|
|
- Notifications may be rate-limited
|
|
- Users can disable notifications per-app
|
|
|
|
---
|
|
|
|
### camera
|
|
|
|
**Description:** Capture photos using the device camera.
|
|
|
|
**Use cases:**
|
|
- Photo capture
|
|
- QR code scanning
|
|
- Augmented reality
|
|
|
|
**API access:**
|
|
```lua
|
|
camera.capture({
|
|
quality = "high",
|
|
facing = "back"
|
|
}, function(result)
|
|
if result.success then
|
|
local imageData = result.data
|
|
end
|
|
end)
|
|
```
|
|
|
|
**Restrictions:**
|
|
- User prompt before first access
|
|
- Cannot record video (photo only)
|
|
|
|
---
|
|
|
|
### microphone
|
|
|
|
**Description:** Record audio from the device microphone.
|
|
|
|
**Use cases:**
|
|
- Voice notes
|
|
- Audio messages
|
|
- Voice commands
|
|
|
|
**API access:**
|
|
```lua
|
|
microphone.start()
|
|
microphone.stop(function(result)
|
|
local audioData = result.data
|
|
end)
|
|
```
|
|
|
|
**Restrictions:**
|
|
- User prompt before first access
|
|
- Maximum recording duration enforced
|
|
|
|
---
|
|
|
|
### location
|
|
|
|
**Description:** Access device location information.
|
|
|
|
**Use cases:**
|
|
- Weather apps
|
|
- Maps
|
|
- Location-based features
|
|
|
|
**API access:**
|
|
```lua
|
|
location.get(function(result)
|
|
if result.success then
|
|
print(result.latitude, result.longitude)
|
|
end
|
|
end)
|
|
|
|
location.watch(function(result)
|
|
-- Called on location changes
|
|
end)
|
|
```
|
|
|
|
**Restrictions:**
|
|
- User prompt before first access
|
|
- Approximate location only (no precise GPS)
|
|
- Battery impact warning
|
|
|
|
---
|
|
|
|
### contacts
|
|
|
|
**Description:** Read device contacts.
|
|
|
|
**Use cases:**
|
|
- Contact picker
|
|
- Address book integration
|
|
- Sharing with friends
|
|
|
|
**API access:**
|
|
```lua
|
|
contacts.pick(function(result)
|
|
if result.success then
|
|
print(result.name, result.phone)
|
|
end
|
|
end)
|
|
|
|
contacts.getAll(function(result)
|
|
for i, contact in ipairs(result.contacts) do
|
|
print(contact.name)
|
|
end
|
|
end)
|
|
```
|
|
|
|
**Restrictions:**
|
|
- Read-only access
|
|
- User prompt before first access
|
|
|
|
## Permission Levels
|
|
|
|
| Level | Description | Example |
|
|
|-------|-------------|---------|
|
|
| **Normal** | Low risk, minimal review | storage |
|
|
| **Sensitive** | Requires user prompt | camera, microphone, location |
|
|
| **Dangerous** | Extensive review required | contacts |
|
|
|
|
## Runtime Behavior
|
|
|
|
### First-Time Prompts
|
|
|
|
Some permissions trigger a user prompt on first use:
|
|
|
|
```lua
|
|
-- First call triggers prompt
|
|
camera.capture(options, function(result)
|
|
if result.denied then
|
|
-- User denied permission
|
|
showPermissionExplanation()
|
|
elseif result.success then
|
|
-- Permission granted
|
|
handlePhoto(result.data)
|
|
end
|
|
end)
|
|
```
|
|
|
|
### Checking Permission Status
|
|
|
|
```lua
|
|
-- Check if permission is granted
|
|
if permissions.check("camera") then
|
|
-- Already have permission
|
|
showCameraButton()
|
|
else
|
|
-- Need to request
|
|
showRequestButton()
|
|
end
|
|
```
|
|
|
|
### Requesting at Runtime
|
|
|
|
```lua
|
|
permissions.request("camera", function(granted)
|
|
if granted then
|
|
startCamera()
|
|
else
|
|
showAlternative()
|
|
end
|
|
end)
|
|
```
|
|
|
|
## Best Practices
|
|
|
|
### 1. Minimize Permissions
|
|
|
|
Only request what you need. An app with fewer permissions:
|
|
- Builds more user trust
|
|
- Passes review faster
|
|
- Has smaller attack surface
|
|
|
|
### 2. Request at the Right Time
|
|
|
|
Don't request all permissions at startup. Request when the user takes an action that needs it:
|
|
|
|
```lua
|
|
-- Bad: Request on app start
|
|
function onAppStart()
|
|
permissions.request("camera") -- Why?
|
|
end
|
|
|
|
-- Good: Request when needed
|
|
function onTakePhotoClicked()
|
|
permissions.request("camera", function(granted)
|
|
if granted then
|
|
camera.capture(options, handlePhoto)
|
|
end
|
|
end)
|
|
end
|
|
```
|
|
|
|
### 3. Explain Why
|
|
|
|
Tell users why you need a permission before requesting:
|
|
|
|
```xml
|
|
<div id="permission-explanation" style="display: none;">
|
|
<p>This app needs camera access to scan QR codes.</p>
|
|
<button onclick="requestCamera()">Enable Camera</button>
|
|
</div>
|
|
```
|
|
|
|
### 4. Handle Denial Gracefully
|
|
|
|
Apps should work (with reduced functionality) even if permissions are denied:
|
|
|
|
```lua
|
|
function capturePhoto()
|
|
if not permissions.check("camera") then
|
|
-- Offer alternative
|
|
showManualEntryOption()
|
|
return
|
|
end
|
|
-- Proceed with camera
|
|
end
|
|
```
|
|
|
|
### 5. Don't Ask Again Immediately
|
|
|
|
If a user denies a permission, don't immediately ask again:
|
|
|
|
```lua
|
|
local lastDenied = storage.get("camera_denied_time")
|
|
if lastDenied and os.time() - lastDenied < 86400 then
|
|
-- Wait at least 24 hours before asking again
|
|
return
|
|
end
|
|
```
|
|
|
|
## Review Impact
|
|
|
|
Permission requests affect app review:
|
|
|
|
| Permission | Review Impact |
|
|
|------------|---------------|
|
|
| storage, network | Automatic approval |
|
|
| clipboard | Quick review |
|
|
| notifications | Standard review |
|
|
| camera, microphone | Extended review |
|
|
| location | Extended review |
|
|
| contacts | Manual review required |
|
|
|
|
Apps requesting sensitive permissions must:
|
|
1. Justify the need in submission notes
|
|
2. Use the permission appropriately
|
|
3. Respect user privacy
|
|
|
|
## Troubleshooting
|
|
|
|
### "Permission not declared"
|
|
|
|
```
|
|
Error: Cannot use camera without 'camera' permission
|
|
```
|
|
|
|
Add the permission to your manifest:
|
|
```json
|
|
"permissions": ["camera"]
|
|
```
|
|
|
|
### "Permission denied by user"
|
|
|
|
Handle this gracefully in your code:
|
|
```lua
|
|
if result.denied then
|
|
showAlternativeUI()
|
|
end
|
|
```
|
|
|
|
### "Permission blocked"
|
|
|
|
The user permanently blocked the permission. Direct them to settings:
|
|
```lua
|
|
if result.blocked then
|
|
showMessage("Please enable camera in system settings")
|
|
end
|
|
```
|
|
|
|
## See Also
|
|
|
|
- [Manifest Reference](../api/manifest.md) - Full manifest documentation
|
|
- [Security Guide](security.md) - App security best practices
|
|
- [Publishing Guide](publishing.md) - App review process
|