|
| 1 | +# iOS Platform API Example Conventions |
| 2 | + |
| 3 | +This document describes the structure conventions for examples in the iOS APIExample project. Please follow these conventions when adding or modifying any examples under `APIExample/APIExample/Examples/`. |
| 4 | + |
| 5 | +## Directory Structure |
| 6 | + |
| 7 | +- **Basic Examples:** `APIExample/APIExample/Examples/Basic/<ExampleName>/` |
| 8 | +- **Advanced Examples:** `APIExample/APIExample/Examples/Advanced/<ExampleName>/` |
| 9 | + |
| 10 | +The folder name is the **example identifier** (e.g., `VideoProcess`, `JoinChannelVideo`), using PascalCase without spaces. |
| 11 | + |
| 12 | +The folder typically contains: |
| 13 | + |
| 14 | +- One or more Swift files (e.g., `VideoProcess.swift`, `JoinChannelVideo.swift`), defining Entry and Main view controllers. |
| 15 | +- One storyboard: `Base.lproj/<ExampleName>.storyboard` (same name as identifier). |
| 16 | + |
| 17 | +## Swift: Entry and Main |
| 18 | + |
| 19 | +Each example contains two view controller roles: |
| 20 | + |
| 21 | +### Entry (Entry Page) |
| 22 | + |
| 23 | +- **Class Name:** `<ExampleName>Entry` (e.g., `VideoProcessEntry`, `JoinChannelVideoEntry`). |
| 24 | +- **Base Class:** `UIViewController`. |
| 25 | +- **Responsibilities:** |
| 26 | + - Provide channel name input field and "Join" button (or equivalent controls). |
| 27 | + - Optional: Collect resolution, frame rate, orientation, etc. (refer to `JoinChannelVideoEntry`). |
| 28 | + - In the "Join" button callback: |
| 29 | + - Read channel name (and any additional required parameters). |
| 30 | + - Load **same-named storyboard**: `UIStoryboard(name: identifier, bundle: nil)`, where `identifier = "<ExampleName>"`. |
| 31 | + - Instantiate Main VC: `storyBoard.instantiateViewController(withIdentifier: identifier) as? BaseViewController`. |
| 32 | + - Set `newViewController.configs`, at least including `"channelName"`, plus other keys needed by Main (e.g., `"resolution"`, `"fps"`, `"orientation"`). |
| 33 | + - Push Main VC: `navigationController?.pushViewController(newViewController, animated: true)`. |
| 34 | + |
| 35 | +### Main (Example Main Logic) |
| 36 | + |
| 37 | +- **Class Name:** `<ExampleName>Main`, or a single class name consistent with Main's identifier in storyboard (if no Main suffix, same as identifier). |
| 38 | +- **Base Class:** `BaseViewController`. |
| 39 | +- **Responsibilities:** |
| 40 | + - Read channel name etc. from `configs` (e.g., `configs["channelName"] as? String`) and options passed from Entry. |
| 41 | + - Create and configure `AgoraRtcEngineKit` (e.g., `KeyCenter.AppId`, `GlobalSettings.shared.area`), call `Util.configPrivatization(agoraKit:)` when needed. |
| 42 | + - Implement specific Agora API calls (join channel, toggle audio/video, etc.). |
| 43 | + - Conform to `AgoraRtcEngineDelegate` and other required protocols. |
| 44 | + |
| 45 | +Reference: `JoinChannelVideo.swift` (Entry + Main), `VideoProcess.swift` (Entry + Main). |
| 46 | + |
| 47 | +## Storyboard |
| 48 | + |
| 49 | +- **File Path:** `APIExample/Examples/<Basic|Advanced>/<ExampleName>/Base.lproj/<ExampleName>.storyboard`. |
| 50 | +- **Two Scenes:** |
| 51 | + |
| 52 | + 1. **Entry Scene** |
| 53 | + - **Storyboard Identifier:** `EntryViewController`. |
| 54 | + - **Custom Class:** `<ExampleName>Entry`, Module: `APIExample`. |
| 55 | + - Connect channel input field and join button to Entry class (outlets and actions). |
| 56 | + |
| 57 | + 2. **Main Scene** |
| 58 | + - **Storyboard Identifier:** `<ExampleName>` (consistent with folder name, e.g., `VideoProcess`, `JoinChannelVideo`). |
| 59 | + - **Custom Class:** `<ExampleName>Main` (or actual Main class name used in code), Module: `APIExample`. |
| 60 | + - Layout example main interface and connect outlets/actions to this class. |
| 61 | + |
| 62 | +- When entering from menu, **Entry is shown first**; after user clicks join, Main is instantiated and pushed in code. |
| 63 | + |
| 64 | +## Menu Registration |
| 65 | + |
| 66 | +- **File:** `APIExample/ViewController.swift`. |
| 67 | +- **Structure:** `menus` is an array of `MenuSection`, each section has `name` (e.g., `"Basic"`, `"Anvanced"`) and `rows: [MenuItem]`. |
| 68 | + |
| 69 | +When adding an example: |
| 70 | + |
| 71 | +- Append a `MenuItem` to the `rows` of the corresponding section. |
| 72 | +- **Field Description:** |
| 73 | + - `name`: Display name in list (can add `.localized` if project uses internationalization). |
| 74 | + - `storyboard`: Storyboard file name (**without** extension), consistent with example identifier, e.g., `"VideoProcess"`, `"JoinChannelVideo"`. |
| 75 | + - `entry`: Usually `"EntryViewController"` (default). |
| 76 | + - `controller`: Main VC's identifier or empty string `""`; since Entry pushes Main in this project, this is often `""` or consistent with Main's storyboard identifier. |
| 77 | + |
| 78 | +Example: |
| 79 | + |
| 80 | +```swift |
| 81 | +MenuItem(name: "Video Process".localized, storyboard: "VideoProcess", controller: "VideoProcess") |
| 82 | +``` |
| 83 | + |
| 84 | +If an example's Entry class or identifier is different (e.g., KtvCopyrightMusic), set `entry` and `controller` accordingly so the main `ViewController` loads the correct initial VC from that storyboard. |
| 85 | + |
| 86 | +## Common Dependencies |
| 87 | + |
| 88 | +- **App ID:** `KeyCenter.AppId`. |
| 89 | +- **Region / Role / Resolution / Frame Rate / Orientation:** `GlobalSettings.shared` (e.g., `GlobalSettings.shared.area`, `getSetting(key: "resolution")`, etc.). |
| 90 | +- **Logging:** `LogUtils`, call `agoraKit.setLogFile(LogUtils.sdkLogPath())` when needed. |
| 91 | +- **Privatization:** After creating engine, call `Util.configPrivatization(agoraKit: agoraKit)`. |
| 92 | +- **Video Layout:** Use `AGEVideoLayout`, `AGEVideoContainer` / `Bundle.loadVideoView` to display local/remote views. |
| 93 | + |
| 94 | +Please keep naming and structure consistent with existing examples (e.g., `JoinChannelVideo`, `VideoProcess`) to maintain unified project style. |
0 commit comments