Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: CI

on:
push:
branches: [main]
pull_request:

concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
test:
runs-on: macos-26
timeout-minutes: 20

steps:
- uses: actions/checkout@v6

- name: Select simulator
id: simulator
shell: bash
run: |
simulator_id="$(xcrun simctl list devices available | awk -F '[()]' '/iPhone/ { print $2; exit }')"
test -n "$simulator_id"
echo "id=$simulator_id" >> "$GITHUB_OUTPUT"

- name: Run tests
run: |
set -o pipefail
xcodebuild test \
-project UnoClient.xcodeproj \
-scheme UnoClient \
-configuration Debug \
-destination 'platform=iOS Simulator,id=${{ steps.simulator.outputs.id }}' \
CODE_SIGNING_ALLOWED=NO
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,17 @@
#
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore

# macOS / editors
.DS_Store
.idea/

## User settings
xcuserdata/

## Build products
DerivedData/
*.xcresult

## Obj-C/Swift specific
*.hmap

Expand Down
8 changes: 8 additions & 0 deletions .swift-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"indentation" : {
"spaces" : 4
},
"lineLength" : 120,
"tabWidth" : 4,
"version" : 1
}
88 changes: 88 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<h1 align="center">UNO for iOS</h1>

<p align="center">
<a href="https://github.com/letsuno/uno-ios"><img src="https://img.shields.io/github/license/letsuno/uno-ios" alt="License" /></a>
<a href="https://github.com/letsuno/uno-ios/actions/workflows/ci.yml"><img src="https://github.com/letsuno/uno-ios/actions/workflows/ci.yml/badge.svg" alt="CI" /></a>
</p>

A native SwiftUI client for playing on self-hosted [UNO Online](https://github.com/letsuno/uno-online) servers from iPhone and iPad.

## Highlights

- Native SwiftUI interface for rooms, spectating, real-time games, and chat
- Password, API key, development-mode, and Passkey authentication
- Configurable house rules with Classic, Party, and Crazy presets
- Bot players with selectable difficulty levels
- Direct Socket.IO communication over WebSocket without a third-party client dependency
- Secure-by-default server connections with HTTPS/WSS for public hosts and HTTP/WS support for local networks

## Requirements

- Xcode 26 or later
- iOS or iPadOS 26 or later
- A compatible self-hosted [UNO Online](https://github.com/letsuno/uno-online) server

## Quick Start

```bash
git clone https://github.com/letsuno/uno-ios.git
cd uno-ios
open UnoClient.xcodeproj
```

Select the `UnoClient` scheme, choose your development team for device signing, and run the app. Enter the base URL of your server on the connection screen.

To verify a release build without code signing:

```bash
xcodebuild build \
-project UnoClient.xcodeproj \
-scheme UnoClient \
-configuration Release \
-destination 'generic/platform=iOS' \
CODE_SIGNING_ALLOWED=NO
```

## Server Connections

Public servers must use HTTPS/WSS. Plaintext HTTP/WS is limited to `localhost`, `.local` hosts, unqualified hostnames, and private or link-local IP addresses for self-hosted development.

Passkeys require the app's Associated Domains entitlement and the server's WebAuthn configuration to use the same relying-party domain. Update `UnoClient/UnoClient.entitlements` when deploying against a different domain.

## Development

Debug builds support these launch environment variables:

- `UNO_TEST_SERVER` and `UNO_TEST_TOKEN` preconfigure a server and login credential.
- `UNO_TEST_FLOW=quickgame` creates a room, adds three bots, and starts a game after login.

Never commit real credentials to project files or shared schemes.

Run the test suite with:

```bash
xcodebuild test \
-project UnoClient.xcodeproj \
-scheme UnoClient \
-destination 'platform=iOS Simulator,name=iPhone 17 Pro'
```

## Project Layout

```text
UnoClient/
App/ # application entry point and launch automation
Core/ # REST, WebSocket, Passkey, and Keychain integration
Models/ # protocol and game models
Stores/ # session, room, and game state
Views/ # SwiftUI screens and components
UnoClientTests/ # endpoint policy, encoding, and game-rule tests
```

## Project Status

This is an unofficial, non-profit community project. It is not affiliated with, sponsored by, or endorsed by Mattel or any other owner of similarly named games. The repository does not include official logos, trademark artwork, or game assets.

## License

[AGPL-3.0](LICENSE)
11 changes: 11 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# 安全策略

## 报告漏洞

请通过 GitHub 的 [Private Vulnerability Reporting](https://github.com/letsuno/uno-ios/security/advisories/new) 私下报告安全问题,不要先创建公开 Issue。

报告中请尽量包含受影响版本、复现步骤、预期影响,以及可用的缓解建议。凭据、访问令牌和个人数据不应出现在公开日志或 Issue 中。

## 支持范围

项目发布正式版本前仅维护默认分支。首个版本发布后,安全修复将优先覆盖最新发布版本。
13 changes: 13 additions & 0 deletions Support/Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsLocalNetworking</key>
<true/>
</dict>
<key>NSLocalNetworkUsageDescription</key>
<string>Connect to game servers on your local network.</string>
</dict>
</plist>
Loading