├── porting
├── .gitignore
├── server
│ ├── .gitignore
│ ├── scrcpy-server
│ └── src
│ │ └── main
│ │ └── java
│ │ └── com
│ │ └── genymobile
│ │ └── scrcpy
│ │ ├── Device.java
│ │ └── Controller.java
├── src
│ ├── main-porting.c
│ ├── process-porting.c
│ ├── audio_player-porting.c
│ ├── decoder-porting.c
│ ├── process-porting.hpp
│ ├── demuxer-porting.c
│ ├── controller-porting.c
│ ├── display-porting.c
│ ├── scrcpy-porting.c
│ ├── screen-porting.c
│ └── process-porting.cpp
├── scripts
│ ├── make-ffmpeg.sh
│ ├── make-scrcpy.sh
│ ├── defines.sh
│ └── make-libsdl.sh
├── include
│ ├── scrcpy-porting.h
│ └── porting.h
├── Makefile
└── cmake
│ └── CMakeLists.txt
├── scrcpy-ios
├── scrcpy-ios
│ ├── en.lproj
│ │ └── Localizable.strings
│ ├── Assets.xcassets
│ │ ├── Contents.json
│ │ ├── AppIcon.appiconset
│ │ │ ├── 20.png
│ │ │ ├── 29.png
│ │ │ ├── 40.png
│ │ │ ├── 50.png
│ │ │ ├── 57.png
│ │ │ ├── 58.png
│ │ │ ├── 60.png
│ │ │ ├── 72.png
│ │ │ ├── 76.png
│ │ │ ├── 80.png
│ │ │ ├── 87.png
│ │ │ ├── 100.png
│ │ │ ├── 1024.png
│ │ │ ├── 114.png
│ │ │ ├── 120.png
│ │ │ ├── 144.png
│ │ │ ├── 152.png
│ │ │ ├── 167.png
│ │ │ ├── 180.png
│ │ │ └── Contents.json
│ │ ├── More.imageset
│ │ │ ├── More@3x.png
│ │ │ └── Contents.json
│ │ ├── Share.imageset
│ │ │ ├── Share@3x.png
│ │ │ └── Contents.json
│ │ ├── BackIcon.imageset
│ │ │ ├── BackIcon@3x.png
│ │ │ └── Contents.json
│ │ ├── HomeIcon.imageset
│ │ │ ├── HomeIcon@3x.png
│ │ │ └── Contents.json
│ │ ├── Refresh.imageset
│ │ │ ├── Refresh@3x.png
│ │ │ └── Contents.json
│ │ ├── TouchIcon.imageset
│ │ │ ├── TouchIcon@3x.png
│ │ │ └── Contents.json
│ │ ├── disconnect.imageset
│ │ │ ├── disconnect@3x.png
│ │ │ └── Contents.json
│ │ ├── LaunchImage.imageset
│ │ │ ├── LaunchImage@2x.png
│ │ │ ├── LaunchImage@3x.png
│ │ │ └── Contents.json
│ │ ├── KeyboardIcon.imageset
│ │ │ ├── KeyboardIcon@3x.png
│ │ │ └── Contents.json
│ │ ├── SwitchAppIcon.imageset
│ │ │ ├── SwitchAppIcon@3x.png
│ │ │ └── Contents.json
│ │ ├── DisconnectIcon.imageset
│ │ │ ├── DisconnectIcon@3x.png
│ │ │ └── Contents.json
│ │ └── LaunchAppIcon.imageset
│ │ │ ├── AppLaunchImage@2x.png
│ │ │ ├── AppLaunchImage@3x.png
│ │ │ └── Contents.json
│ ├── ViewController.h
│ ├── KeysViewController.h
│ ├── LogsViewController.h
│ ├── PairViewController.h
│ ├── MenubarViewController.h
│ ├── ScrcpySwitch.h
│ ├── ScrcpyTextField.h
│ ├── LogManager.h
│ ├── SDL_uikitviewcontroller+Extend.h
│ ├── ScrcpySwitch.m
│ ├── SDLUIKitDelegate+Extend.h
│ ├── Info.plist
│ ├── ScrcpyTextField.m
│ ├── main.m
│ ├── LogManager.m
│ ├── Base.lproj
│ │ ├── Main.storyboard
│ │ └── LaunchScreen.storyboard
│ ├── ScrcpyClient.h
│ ├── SDLUIKitDelegate+Extend.m
│ ├── LogsViewController.m
│ ├── zh-Hans.lproj
│ │ └── Localizable.strings
│ ├── SDL_uikitviewcontroller+Extend.m
│ ├── UICommonUtils.h
│ ├── MenubarViewController.m
│ ├── PairViewController.m
│ ├── KeysViewController.m
│ └── ScrcpyClient.m
├── scrcpy-ios.xcodeproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ ├── xcuserdata
│ │ │ └── ethan.xcuserdatad
│ │ │ │ ├── UserInterfaceState.xcuserstate
│ │ │ │ └── xcdebugger
│ │ │ │ └── Expressions.xcexplist
│ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ ├── xcuserdata
│ │ └── ethan.xcuserdatad
│ │ │ └── xcschemes
│ │ │ └── xcschememanagement.plist
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── scrcpy-ios.xcscheme
└── scrcpy-vnc
│ ├── VNCHTTPConnection.m
│ ├── VNCViewController.h
│ ├── VNCHTTPConnection.h
│ ├── HTTPFileResponse+Extend.h
│ ├── VNCBrowserViewController.h
│ ├── HTTPFileResponse+Extend.m
│ ├── VNCBrowserViewController.m
│ └── VNCViewController.m
├── screenshots
├── telegram.png
├── screenshots.png
└── Download_on_the_App_Store_Badge.png
├── Makefile
├── .gitignore
├── .gitmodules
├── LICENSE
└── README.md
/porting/.gitignore:
--------------------------------------------------------------------------------
1 | out
2 |
--------------------------------------------------------------------------------
/porting/server/.gitignore:
--------------------------------------------------------------------------------
1 | scrcpy.zip
2 | scrcpy-*.*
3 |
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/en.lproj/Localizable.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/screenshots/telegram.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wsvn53/scrcpy-mobile/HEAD/screenshots/telegram.png
--------------------------------------------------------------------------------
/porting/server/scrcpy-server:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wsvn53/scrcpy-mobile/HEAD/porting/server/scrcpy-server
--------------------------------------------------------------------------------
/screenshots/screenshots.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wsvn53/scrcpy-mobile/HEAD/screenshots/screenshots.png
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/screenshots/Download_on_the_App_Store_Badge.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wsvn53/scrcpy-mobile/HEAD/screenshots/Download_on_the_App_Store_Badge.png
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/Assets.xcassets/AppIcon.appiconset/20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wsvn53/scrcpy-mobile/HEAD/scrcpy-ios/scrcpy-ios/Assets.xcassets/AppIcon.appiconset/20.png
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/Assets.xcassets/AppIcon.appiconset/29.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wsvn53/scrcpy-mobile/HEAD/scrcpy-ios/scrcpy-ios/Assets.xcassets/AppIcon.appiconset/29.png
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/Assets.xcassets/AppIcon.appiconset/40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wsvn53/scrcpy-mobile/HEAD/scrcpy-ios/scrcpy-ios/Assets.xcassets/AppIcon.appiconset/40.png
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/Assets.xcassets/AppIcon.appiconset/50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wsvn53/scrcpy-mobile/HEAD/scrcpy-ios/scrcpy-ios/Assets.xcassets/AppIcon.appiconset/50.png
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/Assets.xcassets/AppIcon.appiconset/57.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wsvn53/scrcpy-mobile/HEAD/scrcpy-ios/scrcpy-ios/Assets.xcassets/AppIcon.appiconset/57.png
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/Assets.xcassets/AppIcon.appiconset/58.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wsvn53/scrcpy-mobile/HEAD/scrcpy-ios/scrcpy-ios/Assets.xcassets/AppIcon.appiconset/58.png
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/Assets.xcassets/AppIcon.appiconset/60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wsvn53/scrcpy-mobile/HEAD/scrcpy-ios/scrcpy-ios/Assets.xcassets/AppIcon.appiconset/60.png
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/Assets.xcassets/AppIcon.appiconset/72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wsvn53/scrcpy-mobile/HEAD/scrcpy-ios/scrcpy-ios/Assets.xcassets/AppIcon.appiconset/72.png
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/Assets.xcassets/AppIcon.appiconset/76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wsvn53/scrcpy-mobile/HEAD/scrcpy-ios/scrcpy-ios/Assets.xcassets/AppIcon.appiconset/76.png
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/Assets.xcassets/AppIcon.appiconset/80.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wsvn53/scrcpy-mobile/HEAD/scrcpy-ios/scrcpy-ios/Assets.xcassets/AppIcon.appiconset/80.png
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/Assets.xcassets/AppIcon.appiconset/87.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wsvn53/scrcpy-mobile/HEAD/scrcpy-ios/scrcpy-ios/Assets.xcassets/AppIcon.appiconset/87.png
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/Assets.xcassets/More.imageset/More@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wsvn53/scrcpy-mobile/HEAD/scrcpy-ios/scrcpy-ios/Assets.xcassets/More.imageset/More@3x.png
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | libs: update-all libscrcpy
2 |
3 | update-all:
4 | git submodule update --init --recursive
5 |
6 | libscrcpy:
7 | mkdir -pv output/{iphone,android}
8 | make -C porting
9 |
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/Assets.xcassets/AppIcon.appiconset/100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wsvn53/scrcpy-mobile/HEAD/scrcpy-ios/scrcpy-ios/Assets.xcassets/AppIcon.appiconset/100.png
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/Assets.xcassets/AppIcon.appiconset/1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wsvn53/scrcpy-mobile/HEAD/scrcpy-ios/scrcpy-ios/Assets.xcassets/AppIcon.appiconset/1024.png
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/Assets.xcassets/AppIcon.appiconset/114.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wsvn53/scrcpy-mobile/HEAD/scrcpy-ios/scrcpy-ios/Assets.xcassets/AppIcon.appiconset/114.png
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/Assets.xcassets/AppIcon.appiconset/120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wsvn53/scrcpy-mobile/HEAD/scrcpy-ios/scrcpy-ios/Assets.xcassets/AppIcon.appiconset/120.png
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/Assets.xcassets/AppIcon.appiconset/144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wsvn53/scrcpy-mobile/HEAD/scrcpy-ios/scrcpy-ios/Assets.xcassets/AppIcon.appiconset/144.png
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/Assets.xcassets/AppIcon.appiconset/152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wsvn53/scrcpy-mobile/HEAD/scrcpy-ios/scrcpy-ios/Assets.xcassets/AppIcon.appiconset/152.png
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/Assets.xcassets/AppIcon.appiconset/167.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wsvn53/scrcpy-mobile/HEAD/scrcpy-ios/scrcpy-ios/Assets.xcassets/AppIcon.appiconset/167.png
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/Assets.xcassets/AppIcon.appiconset/180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wsvn53/scrcpy-mobile/HEAD/scrcpy-ios/scrcpy-ios/Assets.xcassets/AppIcon.appiconset/180.png
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/Assets.xcassets/Share.imageset/Share@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wsvn53/scrcpy-mobile/HEAD/scrcpy-ios/scrcpy-ios/Assets.xcassets/Share.imageset/Share@3x.png
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/Assets.xcassets/BackIcon.imageset/BackIcon@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wsvn53/scrcpy-mobile/HEAD/scrcpy-ios/scrcpy-ios/Assets.xcassets/BackIcon.imageset/BackIcon@3x.png
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/Assets.xcassets/HomeIcon.imageset/HomeIcon@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wsvn53/scrcpy-mobile/HEAD/scrcpy-ios/scrcpy-ios/Assets.xcassets/HomeIcon.imageset/HomeIcon@3x.png
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/Assets.xcassets/Refresh.imageset/Refresh@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wsvn53/scrcpy-mobile/HEAD/scrcpy-ios/scrcpy-ios/Assets.xcassets/Refresh.imageset/Refresh@3x.png
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/Assets.xcassets/TouchIcon.imageset/TouchIcon@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wsvn53/scrcpy-mobile/HEAD/scrcpy-ios/scrcpy-ios/Assets.xcassets/TouchIcon.imageset/TouchIcon@3x.png
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/Assets.xcassets/disconnect.imageset/disconnect@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wsvn53/scrcpy-mobile/HEAD/scrcpy-ios/scrcpy-ios/Assets.xcassets/disconnect.imageset/disconnect@3x.png
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wsvn53/scrcpy-mobile/HEAD/scrcpy-ios/scrcpy-ios/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wsvn53/scrcpy-mobile/HEAD/scrcpy-ios/scrcpy-ios/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/Assets.xcassets/KeyboardIcon.imageset/KeyboardIcon@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wsvn53/scrcpy-mobile/HEAD/scrcpy-ios/scrcpy-ios/Assets.xcassets/KeyboardIcon.imageset/KeyboardIcon@3x.png
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/Assets.xcassets/SwitchAppIcon.imageset/SwitchAppIcon@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wsvn53/scrcpy-mobile/HEAD/scrcpy-ios/scrcpy-ios/Assets.xcassets/SwitchAppIcon.imageset/SwitchAppIcon@3x.png
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/Assets.xcassets/DisconnectIcon.imageset/DisconnectIcon@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wsvn53/scrcpy-mobile/HEAD/scrcpy-ios/scrcpy-ios/Assets.xcassets/DisconnectIcon.imageset/DisconnectIcon@3x.png
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/Assets.xcassets/LaunchAppIcon.imageset/AppLaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wsvn53/scrcpy-mobile/HEAD/scrcpy-ios/scrcpy-ios/Assets.xcassets/LaunchAppIcon.imageset/AppLaunchImage@2x.png
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/Assets.xcassets/LaunchAppIcon.imageset/AppLaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wsvn53/scrcpy-mobile/HEAD/scrcpy-ios/scrcpy-ios/Assets.xcassets/LaunchAppIcon.imageset/AppLaunchImage@3x.png
--------------------------------------------------------------------------------
/porting/src/main-porting.c:
--------------------------------------------------------------------------------
1 | //
2 | // main-porting.c
3 | // scrcpy-mobile
4 | //
5 | // Created by Ethan on 2022/6/2.
6 | //
7 |
8 | #define main(...) scrcpy_main(__VA_ARGS__)
9 |
10 | #include "main.c"
11 |
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/ViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.h
3 | // scrcpy-ios
4 | //
5 | // Created by Ethan on 2022/6/2.
6 | //
7 |
8 | #import
9 |
10 | @interface ViewController : UIViewController
11 | @end
12 |
13 |
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios.xcodeproj/project.xcworkspace/xcuserdata/ethan.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wsvn53/scrcpy-mobile/HEAD/scrcpy-ios/scrcpy-ios.xcodeproj/project.xcworkspace/xcuserdata/ethan.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-vnc/VNCHTTPConnection.m:
--------------------------------------------------------------------------------
1 | //
2 | // VNCHTTPConnection.m
3 | // scrcpy-ios
4 | //
5 | // Created by Ethan on 2022/6/15.
6 | //
7 |
8 | #import "VNCHTTPConnection.h"
9 | #import "HTTPFileResponse.h"
10 |
11 | @implementation VNCHTTPConnection
12 | @end
13 |
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-vnc/VNCViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // VNCViewController.h
3 | // scrcpy-ios
4 | //
5 | // Created by Ethan on 2022/6/15.
6 | //
7 |
8 | #import
9 |
10 | NS_ASSUME_NONNULL_BEGIN
11 |
12 | @interface VNCViewController : UIViewController
13 |
14 | @end
15 |
16 | NS_ASSUME_NONNULL_END
17 |
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/KeysViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // KeysViewController.h
3 | // scrcpy-ios
4 | //
5 | // Created by Ethan on 27/12/22.
6 | //
7 |
8 | #import
9 |
10 | NS_ASSUME_NONNULL_BEGIN
11 |
12 | @interface KeysViewController : UIViewController
13 |
14 | @end
15 |
16 | NS_ASSUME_NONNULL_END
17 |
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/LogsViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // LogsViewController.h
3 | // scrcpy-ios
4 | //
5 | // Created by Ethan on 2022/7/20.
6 | //
7 |
8 | #import
9 |
10 | NS_ASSUME_NONNULL_BEGIN
11 |
12 | @interface LogsViewController : UIViewController
13 |
14 | @end
15 |
16 | NS_ASSUME_NONNULL_END
17 |
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/PairViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // PairViewController.h
3 | // scrcpy-ios
4 | //
5 | // Created by Ethan on 2022/7/18.
6 | //
7 |
8 | #import
9 |
10 | NS_ASSUME_NONNULL_BEGIN
11 |
12 | @interface PairViewController : UIViewController
13 |
14 | @end
15 |
16 | NS_ASSUME_NONNULL_END
17 |
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-vnc/VNCHTTPConnection.h:
--------------------------------------------------------------------------------
1 | //
2 | // VNCHTTPConnection.h
3 | // scrcpy-ios
4 | //
5 | // Created by Ethan on 2022/6/15.
6 | //
7 |
8 | #import "HTTPConnection.h"
9 |
10 | NS_ASSUME_NONNULL_BEGIN
11 |
12 | @interface VNCHTTPConnection : HTTPConnection
13 |
14 | @end
15 |
16 | NS_ASSUME_NONNULL_END
17 |
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-vnc/HTTPFileResponse+Extend.h:
--------------------------------------------------------------------------------
1 | //
2 | // HTTPFileResponse+Extend.h
3 | // scrcpy-ios
4 | //
5 | // Created by Ethan on 2022/6/16.
6 | //
7 |
8 | #import "HTTPFileResponse.h"
9 |
10 | NS_ASSUME_NONNULL_BEGIN
11 |
12 | @interface HTTPFileResponse (Extend)
13 |
14 | @end
15 |
16 | NS_ASSUME_NONNULL_END
17 |
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/MenubarViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // MenubarViewController.h
3 | // scrcpy-ios
4 | //
5 | // Created by Ethan on 2022/6/28.
6 | //
7 |
8 | #import
9 |
10 | NS_ASSUME_NONNULL_BEGIN
11 |
12 | @interface MenubarViewController : UIViewController
13 |
14 | @end
15 |
16 | NS_ASSUME_NONNULL_END
17 |
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/ScrcpySwitch.h:
--------------------------------------------------------------------------------
1 | //
2 | // ScrcpySwitch.h
3 | // scrcpy-ios
4 | //
5 | // Created by Ethan on 2022/6/14.
6 | //
7 |
8 | #import
9 |
10 | NS_ASSUME_NONNULL_BEGIN
11 |
12 | @interface ScrcpySwitch : UISwitch
13 |
14 | @property (nonatomic, copy) NSString *optionKey;
15 |
16 | -(void)updateOptionValue;
17 |
18 | @end
19 |
20 | NS_ASSUME_NONNULL_END
21 |
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/ScrcpyTextField.h:
--------------------------------------------------------------------------------
1 | //
2 | // ScrcpyTextField.h
3 | // scrcpy-ios
4 | //
5 | // Created by Ethan on 2022/6/12.
6 | //
7 |
8 | #import
9 |
10 | NS_ASSUME_NONNULL_BEGIN
11 |
12 | @interface ScrcpyTextField : UITextField
13 |
14 | @property (nonatomic, copy) NSString *optionKey;
15 |
16 | -(void)updateOptionValue;
17 |
18 | @end
19 |
20 | NS_ASSUME_NONNULL_END
21 |
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/LogManager.h:
--------------------------------------------------------------------------------
1 | //
2 | // LogManager.h
3 | // scrcpy-ios
4 | //
5 | // Created by Ethan on 2022/7/19.
6 | //
7 |
8 | #import
9 |
10 | NS_ASSUME_NONNULL_BEGIN
11 |
12 | @interface LogManager : NSObject
13 |
14 | +(instancetype)sharedManager;
15 |
16 | -(void)startHandleLog;
17 |
18 | -(NSString *)recentLogs;
19 |
20 | @end
21 |
22 | NS_ASSUME_NONNULL_END
23 |
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/SDL_uikitviewcontroller+Extend.h:
--------------------------------------------------------------------------------
1 | //
2 | // SDL_uikitviewcontroller+Extend.h
3 | // scrcpy-ios
4 | //
5 | // Created by Ethan on 2022/6/11.
6 | //
7 |
8 | #import
9 |
10 | NS_ASSUME_NONNULL_BEGIN
11 |
12 | @interface SDL_uikitviewcontroller : UIViewController
13 | @end
14 |
15 | @interface SDL_uikitviewcontroller (Extend)
16 |
17 | @end
18 |
19 | NS_ASSUME_NONNULL_END
20 |
--------------------------------------------------------------------------------
/porting/scripts/make-ffmpeg.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | OUTPUT=$(cd $OUTPUT && pwd);
4 | BUILD_DIR=$(mktemp -d -t ffmpeg);
5 | cd $BUILD_DIR;
6 |
7 | curl -O -L https://downloads.sourceforge.net/project/ffmpeg-ios/ffmpeg-ios-master.tar.bz2;
8 | bunzip2 ffmpeg-ios*.bz2;
9 | tar xvf ffmpeg-ios*.tar;
10 | cp -av FFmpeg-iOS/include/* $OUTPUT/include;
11 | cp -av FFmpeg-iOS/lib/* $OUTPUT/iphone;
12 |
13 | [[ -d "$BUILD_DIR" ]] && rm -rf $BUILD_DIR;
14 |
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/Assets.xcassets/More.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "scale" : "2x"
10 | },
11 | {
12 | "filename" : "More@3x.png",
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/Assets.xcassets/Share.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "scale" : "2x"
10 | },
11 | {
12 | "filename" : "Share@3x.png",
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-vnc/VNCBrowserViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // VNCBrowserViewController.h
3 | // scrcpy-ios
4 | //
5 | // Created by Ethan on 2022/6/15.
6 | //
7 |
8 | #import
9 |
10 | NS_ASSUME_NONNULL_BEGIN
11 |
12 | @interface VNCBrowserViewController : UIViewController
13 |
14 | @property (nonatomic, copy) NSString *vncURL;
15 | @property (nonatomic, assign) BOOL showsFullscreen;
16 |
17 | @end
18 |
19 | NS_ASSUME_NONNULL_END
20 |
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/Assets.xcassets/Refresh.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "scale" : "2x"
10 | },
11 | {
12 | "filename" : "Refresh@3x.png",
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/Assets.xcassets/BackIcon.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "scale" : "2x"
10 | },
11 | {
12 | "filename" : "BackIcon@3x.png",
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/Assets.xcassets/HomeIcon.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "scale" : "2x"
10 | },
11 | {
12 | "filename" : "HomeIcon@3x.png",
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/Assets.xcassets/TouchIcon.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "scale" : "2x"
10 | },
11 | {
12 | "filename" : "TouchIcon@3x.png",
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/Assets.xcassets/disconnect.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "scale" : "2x"
10 | },
11 | {
12 | "filename" : "disconnect@3x.png",
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/Assets.xcassets/KeyboardIcon.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "scale" : "2x"
10 | },
11 | {
12 | "filename" : "KeyboardIcon@3x.png",
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/Assets.xcassets/DisconnectIcon.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "scale" : "2x"
10 | },
11 | {
12 | "filename" : "DisconnectIcon@3x.png",
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/Assets.xcassets/SwitchAppIcon.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "scale" : "2x"
10 | },
11 | {
12 | "filename" : "SwitchAppIcon@3x.png",
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios.xcodeproj/xcuserdata/ethan.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | scrcpy-ios.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 0
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/porting/include/scrcpy-porting.h:
--------------------------------------------------------------------------------
1 | //
2 | // scrcpy.h
3 | // scrcpy-mobile
4 | //
5 | // Created by Ethan on 2022/6/2.
6 | //
7 |
8 | #ifndef scrcpy_h
9 | #define scrcpy_h
10 |
11 | #include
12 | int scrcpy_main(int argc, char *argv[]);
13 |
14 | enum ScrcpyStatus {
15 | ScrcpyStatusDisconnected = 0,
16 | ScrcpyStatusConnecting,
17 | ScrcpyStatusConnectingFailed,
18 | ScrcpyStatusConnected,
19 | };
20 | void ScrcpyUpdateStatus(enum ScrcpyStatus status);
21 |
22 | #endif /* scrcpy_h */
23 |
--------------------------------------------------------------------------------
/porting/scripts/make-scrcpy.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | . $(dirname $0)/defines.sh;
4 |
5 | cmake_root=./cmake/out;
6 |
7 | # Clean built products
8 | [[ -d "$cmake_root" ]] && rm -rfv "$cmake_root";
9 | mkdir -pv "$cmake_root";
10 |
11 | cd "$cmake_root";
12 |
13 | cmake .. -G Xcode -DCMAKE_TOOLCHAIN_FILE=$CMAKE_TOOLCHAIN_FILE -DPLATFORM=$PLATFORM \
14 | -DDEPLOYMENT_TARGET=$DEPLOYMENT_TARGET;
15 | cmake --build . --config Debug --target scrcpy --parallel 8;
16 | find . -name "*.a" -exec cp -av {} $FULL_OUTPUT \;
17 |
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/Assets.xcassets/LaunchImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "LaunchImage@2x.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "LaunchImage@3x.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/Assets.xcassets/LaunchAppIcon.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "AppLaunchImage@2x.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "AppLaunchImage@3x.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/ScrcpySwitch.m:
--------------------------------------------------------------------------------
1 | //
2 | // ScrcpySwitch.m
3 | // scrcpy-ios
4 | //
5 | // Created by Ethan on 2022/6/14.
6 | //
7 |
8 | #import "ScrcpySwitch.h"
9 | #import "KFKeychain.h"
10 |
11 | @implementation ScrcpySwitch
12 |
13 | -(void)setOptionKey:(NSString *)optionKey {
14 | _optionKey = optionKey;
15 | NSNumber *optionValue = [KFKeychain loadObjectForKey:optionKey];
16 | if (optionValue) {
17 | self.on = [optionValue boolValue];
18 | }
19 | }
20 |
21 | -(void)updateOptionValue {
22 | [KFKeychain saveObject:@(self.on) forKey:self.optionKey];
23 | }
24 |
25 | @end
26 |
--------------------------------------------------------------------------------
/porting/include/porting.h:
--------------------------------------------------------------------------------
1 | //
2 | // porting.h
3 | // scrcpy
4 | //
5 | // Created by Ethan on 2022/6/2.
6 | //
7 |
8 | #ifndef porting_h
9 | #define porting_h
10 |
11 | #include
12 | #include
13 |
14 | typedef GLfloat GLdouble;
15 | typedef double GLclampd;
16 |
17 | #include
18 |
19 | // Define NDEBUG will define assert -> (void)0, see assert.h
20 | // This will prevent to_fixed_point_16 crashed
21 | #define NDEBUG 1
22 |
23 | // Because conflicted function name with adb, rename it
24 | #define adb_connect(...) adb_connect__(__VA_ARGS__)
25 |
26 | #endif /* porting_h */
27 |
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-vnc/HTTPFileResponse+Extend.m:
--------------------------------------------------------------------------------
1 | //
2 | // HTTPFileResponse+Extend.m
3 | // scrcpy-ios
4 | //
5 | // Created by Ethan on 2022/6/16.
6 | //
7 |
8 | #import "HTTPFileResponse+Extend.h"
9 |
10 | @implementation HTTPFileResponse (Extend)
11 |
12 | -(NSDictionary *)httpHeaders {
13 | if ([self.filePath hasSuffix:@".svg"]) {
14 | return @{
15 | @"Content-Type": @"image/svg+xml"
16 | };
17 | }
18 |
19 | if ([self.filePath hasSuffix:@".js"]) {
20 | return @{
21 | @"Content-Type": @"application/javascript"
22 | };
23 | }
24 |
25 | return @{};
26 | }
27 |
28 | @end
29 |
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios.xcodeproj/project.xcworkspace/xcuserdata/ethan.xcuserdatad/xcdebugger/Expressions.xcexplist:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
7 |
8 |
10 |
11 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Prerequisites
2 | *.d
3 |
4 | # Object files
5 | *.o
6 | *.ko
7 | *.obj
8 | *.elf
9 |
10 | # Linker output
11 | *.ilk
12 | *.map
13 | *.exp
14 |
15 | # Precompiled Headers
16 | *.gch
17 | *.pch
18 |
19 | # Libraries
20 | *.lib
21 | *.a
22 | *.la
23 | *.lo
24 |
25 | # Shared objects (inc. Windows DLLs)
26 | *.dll
27 | *.so
28 | *.so.*
29 | *.dylib
30 |
31 | # Executables
32 | *.exe
33 | *.out
34 | *.app
35 | *.i*86
36 | *.x86_64
37 | *.hex
38 |
39 | # Debug files
40 | *.dSYM/
41 | *.su
42 | *.idb
43 | *.pdb
44 |
45 | # Kernel Module Compile Results
46 | *.mod*
47 | *.cmd
48 | .tmp_versions/
49 | modules.order
50 | Module.symvers
51 | Mkfile.old
52 | dkms.conf
53 | output
54 |
--------------------------------------------------------------------------------
/porting/src/process-porting.c:
--------------------------------------------------------------------------------
1 | //
2 | // process-fix.c
3 | // scrcpy-module
4 | //
5 | // Created by Ethan on 2022/2/10.
6 | //
7 |
8 | #include "util/process.c"
9 |
10 | // Handle sc_process_execute_p to execute adb commands via libadb
11 | #define sc_process_execute_p(...) sc_process_execute_p__hijack(__VA_ARGS__)
12 | #define sc_pipe_read_all_intr(...) sc_pipe_read_all_intr__hijack(__VA_ARGS__)
13 | #define sc_process_wait(...) sc_process_wait__hijack(__VA_ARGS__)
14 | #define sc_process_terminate(...) sc_process_terminate__hijack(__VA_ARGS__)
15 |
16 | #include "sys/unix/process.c"
17 | #include "util/process_intr.c"
18 |
19 | #undef sc_process_execute_p
20 | #undef sc_pipe_read_all_intr
21 | #undef sc_process_wait
22 | #undef sc_process_terminate
23 |
--------------------------------------------------------------------------------
/porting/src/audio_player-porting.c:
--------------------------------------------------------------------------------
1 | //
2 | // audio_player-porting.c
3 | // scrcpy-module
4 | //
5 | // Created by Ethan on 2023/5/21.
6 | //
7 | #include
8 | #include
9 |
10 | #define swr_convert(...) swr_convert_hijack(__VA_ARGS__)
11 |
12 | #include "audio_player.c"
13 |
14 | #undef swr_convert
15 |
16 | int swr_convert(struct SwrContext *s, uint8_t **out, int out_count,
17 | const uint8_t **in , int in_count);
18 | int swr_convert_hijack(struct SwrContext *s, uint8_t **out, int out_count,
19 | const uint8_t **in , int in_count) {
20 | // TODO: resample audio with accelerated API
21 | return swr_convert(s, out, out_count, in, in_count);
22 | }
23 |
24 |
--------------------------------------------------------------------------------
/porting/src/decoder-porting.c:
--------------------------------------------------------------------------------
1 | //
2 | // decoder-porting.c
3 | // scrcpy-module
4 | //
5 | // Created by Ethan on 2022/6/8.
6 | //
7 |
8 | #define avcodec_send_packet(...) avcodec_send_packet_hijack(__VA_ARGS__)
9 |
10 | #include "decoder.c"
11 |
12 | #undef avcodec_send_packet
13 |
14 | bool ScrcpyEnableHardwareDecoding(void);
15 | int avcodec_send_packet(AVCodecContext *avctx, const AVPacket *avpkt);
16 | int avcodec_send_packet_hijack(AVCodecContext *avctx, const AVPacket *avpkt) {
17 | int ret = avcodec_send_packet(avctx, avpkt);
18 |
19 | if (ret == AVERROR_UNKNOWN && ScrcpyEnableHardwareDecoding()) {
20 | // Fix Hardware Decoding Error After Return From Background
21 | return 0;
22 | }
23 |
24 | return ret;
25 | }
26 |
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/SDLUIKitDelegate+Extend.h:
--------------------------------------------------------------------------------
1 | //
2 | // SDLUIKitDelegate+Extend.h
3 | // scrcpy-ios
4 | //
5 | // Created by Ethan on 2022/6/11.
6 | //
7 |
8 | #import
9 |
10 | NS_ASSUME_NONNULL_BEGIN
11 |
12 | #define ScrcpyConnectWithSchemeNotification @"ScrcpyConnectWithSchemeNotification"
13 | #define ScrcpyConnectWithSchemeURLKey @"URL"
14 |
15 | #define ScrcpySwitchModeCommand @"switch"
16 | #define ScrcpySwitchModeKey @"mode"
17 | #define ScrcpyModeVNC @"vnc"
18 | #define ScrcpyModeADB @"adb"
19 |
20 | void ScrcpyReloadViewController(UIWindow *window);
21 |
22 | @interface SDLUIKitDelegate : NSObject
23 | @end
24 |
25 | @interface SDLUIKitDelegate (Extend)
26 | @end
27 |
28 | NS_ASSUME_NONNULL_END
29 |
--------------------------------------------------------------------------------
/porting/src/process-porting.hpp:
--------------------------------------------------------------------------------
1 | //
2 | // process-porting.hpp
3 | // scrcpy
4 | //
5 | // Created by Ethan on 2022/3/19.
6 | //
7 |
8 | #ifndef process_porting_hpp
9 | #define process_porting_hpp
10 |
11 | #include
12 | #include
13 |
14 | #ifdef __cplusplus
15 | extern "C" {
16 | #endif
17 |
18 | typedef pid_t sc_pid;
19 | typedef int sc_exit_code;
20 | typedef int sc_pipe;
21 |
22 | int
23 | sc_process_execute_p(const char *const argv[], sc_pid *pid, unsigned flags,
24 | int *pin, int *pout, int *perr);
25 | ssize_t
26 | sc_pipe_read_all_intr(struct sc_intr *intr, sc_pid pid, sc_pipe pipe,
27 | char *data, size_t len);
28 | sc_exit_code
29 | sc_process_wait(pid_t pid, bool close);
30 | bool
31 | sc_process_terminate(pid_t pid);
32 |
33 | #ifdef __cplusplus
34 | }
35 | #endif
36 |
37 | #endif /* process_porting_hpp */
38 |
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | BGTaskSchedulerPermittedIdentifiers
6 |
7 | com.mobile.scrcpy-ios.task
8 |
9 | CFBundleURLTypes
10 |
11 |
12 | CFBundleURLName
13 | com.mobile.scrcpy-ios
14 | CFBundleURLSchemes
15 |
16 | scrcpy2
17 |
18 |
19 |
20 | ITSAppUsesNonExemptEncryption
21 |
22 | UIBackgroundModes
23 |
24 | fetch
25 | processing
26 |
27 | UIViewControllerBasedStatusBarAppearance
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/ScrcpyTextField.m:
--------------------------------------------------------------------------------
1 | //
2 | // ScrcpyTextField.m
3 | // scrcpy-ios
4 | //
5 | // Created by Ethan on 2022/6/12.
6 | //
7 |
8 | #import "ScrcpyTextField.h"
9 | #import "KFKeychain.h"
10 |
11 | @implementation ScrcpyTextField
12 |
13 | -(void)setOptionKey:(NSString *)optionKey {
14 | _optionKey = optionKey;
15 | self.text = [KFKeychain loadObjectForKey:optionKey];
16 | }
17 |
18 | -(void)updateOptionValue {
19 | [KFKeychain saveObject:self.text forKey:self.optionKey];
20 | }
21 |
22 | -(CGRect)textRectForBounds:(CGRect)bounds {
23 | return UIEdgeInsetsInsetRect(bounds, UIEdgeInsetsMake(0, 6, 0, 6));
24 | }
25 |
26 | -(CGRect)placeholderRectForBounds:(CGRect)bounds {
27 | return UIEdgeInsetsInsetRect(bounds, UIEdgeInsetsMake(0, 6, 0, 6));
28 | }
29 |
30 | -(CGRect)editingRectForBounds:(CGRect)bounds {
31 | return UIEdgeInsetsInsetRect(bounds, UIEdgeInsetsMake(0, 6, 0, 6));
32 | }
33 |
34 | @end
35 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "scrcpy"]
2 | path = scrcpy
3 | url = https://github.com/Genymobile/scrcpy.git
4 | [submodule "external/adb-mobile"]
5 | path = external/adb-mobile
6 | url = https://github.com/wsvn53/adb-mobile.git
7 | [submodule "ios-cmake"]
8 | path = ios-cmake
9 | url = https://github.com/leetal/ios-cmake.git
10 | [submodule "scrcpy-ios/chainable-view"]
11 | path = scrcpy-ios/chainable-view
12 | url = https://github.com/wsvn53/chainable-view.git
13 | [submodule "scrcpy-ios/Keychain-iOS-ObjC"]
14 | path = scrcpy-ios/Keychain-iOS-ObjC
15 | url = https://github.com/Keyflow/Keychain-iOS-ObjC.git
16 | [submodule "scrcpy-ios/MBProgressHUD"]
17 | path = scrcpy-ios/MBProgressHUD
18 | url = https://github.com/jdg/MBProgressHUD.git
19 | [submodule "scrcpy-ios/CocoaHTTPServer"]
20 | path = scrcpy-ios/CocoaHTTPServer
21 | url = https://github.com/robbiehanson/CocoaHTTPServer.git
22 | [submodule "scrcpy-ios/noVNC"]
23 | path = scrcpy-ios/noVNC
24 | url = https://github.com/novnc/noVNC.git
25 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Ethan
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.
22 |
--------------------------------------------------------------------------------
/porting/scripts/defines.sh:
--------------------------------------------------------------------------------
1 | # Common Supports:
2 | # - TARGET=lz4/iphoneos/arm64
3 | # - OUTPUT=...
4 |
5 | [[ -z "$TARGET" ]] && echo "** ERROR: TARGET is REQUIRED." && exit 1;
6 | [[ -z "$OUTPUT" ]] && echo "** ERROR: OUTPUT is REQUIRED." && exit 1;
7 |
8 | LIB_NAME=$(echo "$TARGET" | cut -d/ -f1);
9 | SDK_NAME=$(echo "$TARGET" | cut -d/ -f2);
10 | ARCH_NAME=$(echo "$TARGET" | cut -d/ -f3);
11 |
12 | # Src root
13 | SOURCE_ROOT=$(cd $(dirname $0)/../.. && pwd);
14 |
15 | # Porting root
16 | PORTING_ROOT=$SOURCE_ROOT/porting;
17 |
18 | # Prepare output path
19 | FULL_OUTPUT=$(cd $OUTPUT && pwd)/$SDK_NAME/$ARCH_NAME;
20 | [[ ! -d $FULL_OUTPUT ]] && mkdir -p $FULL_OUTPUT;
21 |
22 | # For iphone, change to platform
23 | PLATFORM=$([[ $SDK_NAME == iphoneos ]] && echo "OS64" || echo "SIMULATOR64");
24 |
25 | # Setup iphone deploy target
26 | DEPLOYMENT_TARGET=11.0;
27 |
28 | # Setup toolchains
29 | if [[ $SDK_NAME == *iphone* ]]; then
30 | CMAKE_TOOLCHAIN_FILE=$SOURCE_ROOT/ios-cmake/ios.toolchain.cmake;
31 | fi
32 |
33 | # Print summary
34 | echo " - Lib Name: $LIB_NAME";
35 | echo " - SDK Name: $SDK_NAME";
36 | echo " - Arch Name: $ARCH_NAME";
37 | echo " - CMake Toolchain: $CMAKE_TOOLCHAIN_FILE";
38 |
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // scrcpy-ios
4 | //
5 | // Created by Ethan on 2022/6/2.
6 | //
7 |
8 | #import
9 | #import
10 | #import "KFKeychain.h"
11 | #import "config.h"
12 |
13 | #import "SDLUIKitDelegate+Extend.h"
14 | #import "ViewController.h"
15 | #import "VNCViewController.h"
16 |
17 | int main(int argc, char * argv[]) {
18 | NSLog(@"Hello scrcpy v%s", SCRCPY_VERSION);
19 |
20 | static UIWindow *window = nil;
21 | window = window ?: [[UIWindow alloc] init];
22 | ScrcpyReloadViewController(window);
23 | [window makeKeyAndVisible];
24 |
25 | return 0;
26 | }
27 |
28 | void ScrcpyReloadViewController(UIWindow *window) {
29 | UIViewController *mainController = nil;
30 | NSString *mode = [KFKeychain loadObjectForKey:ScrcpySwitchModeKey];
31 | if ([mode isEqualToString:@"adb"]) {
32 | // mainController = [[ScrcpyViewController alloc] initWithNibName:nil bundle:nil];
33 | mainController = [[ViewController alloc] initWithNibName:nil bundle:nil];
34 | } else if (mode.length == 0 || [mode isEqualToString:@"vnc"]) {
35 | mainController = [[VNCViewController alloc] initWithNibName:nil bundle:nil];
36 | }
37 | window.rootViewController = [[UINavigationController alloc] initWithRootViewController:mainController];
38 | }
39 |
--------------------------------------------------------------------------------
/porting/src/demuxer-porting.c:
--------------------------------------------------------------------------------
1 | //
2 | // demuxer-porting.c
3 | // scrcpy-module
4 | //
5 | // Created by Ethan on 2023/5/20.
6 | //
7 |
8 | #define avcodec_alloc_context3(...) avcodec_alloc_context3_hijack(__VA_ARGS__)
9 |
10 | #include "demuxer.c"
11 |
12 | #undef avcodec_alloc_context3
13 |
14 | bool ScrcpyEnableHardwareDecoding(void);
15 |
16 | AVCodecContext *avcodec_alloc_context3(const AVCodec *codec);
17 | AVCodecContext *avcodec_alloc_context3_hijack(const AVCodec *codec) {
18 | AVCodecContext *context = avcodec_alloc_context3(codec);
19 |
20 | if (context->codec_type != AVMEDIA_TYPE_VIDEO ||
21 | ScrcpyEnableHardwareDecoding() == false) {
22 | printf("hardware decoding is disabled\n");
23 | return context;
24 | }
25 |
26 | // Create context with hardware decoder
27 | AVBufferRef *codec_buf;
28 | const char *codecName = av_hwdevice_get_type_name(AV_HWDEVICE_TYPE_VIDEOTOOLBOX);
29 | enum AVHWDeviceType type = av_hwdevice_find_type_by_name(codecName);
30 | int ret = av_hwdevice_ctx_create(&codec_buf, type, NULL, NULL, 0);
31 | if (ret == 0) {
32 | context->hw_device_ctx = av_buffer_ref(codec_buf);
33 | return context;
34 | }
35 |
36 | printf("[WARN] Init hardware decoder FAILED, fallback to foftware decoder.");
37 | return context;
38 | }
39 |
40 |
--------------------------------------------------------------------------------
/porting/Makefile:
--------------------------------------------------------------------------------
1 | all: scrcpy-init adb-mobile libsdl ffmpeg scrcpy scrcpy-server
2 |
3 | scrcpy-init:
4 | cd ../scrcpy && rm -rf x && meson x --buildtype release --strip -Db_lto=true -Dportable=true -Dusb=false
5 |
6 | adb-mobile:
7 | make -C ../external/adb-mobile
8 |
9 | libsdl:
10 | OUTPUT=../output bash ./scripts/make-libsdl.sh
11 |
12 | ffmpeg:
13 | OUTPUT=../output bash ./scripts/make-ffmpeg.sh
14 |
15 | scrcpy:
16 | OUTPUT=../output TARGET=scrcpy/iphoneos/arm64 bash ./scripts/make-scrcpy.sh
17 | OUTPUT=../output TARGET=scrcpy/iphonesimulator/x86_64 bash ./scripts/make-scrcpy.sh
18 | lipo -create ../output/*/*/libscrcpy.a -output ../output/iphone/libscrcpy.a
19 |
20 | scrcpy-server:
21 | set -x && \
22 | export SCRCPY_VERSION=2.3 && \
23 | export ANDROID_SDK_ROOT=~/Library/Android/sdk && \
24 | export JAVA_HOME="$$(/usr/libexec/java_home --version 1.11)" && \
25 | export PATH="$$JAVA_HOME/bin:$$PATH" && \
26 | cd server && rm -rf scrcpy-* && \
27 | curl -o scrcpy.zip -L https://github.com/Genymobile/scrcpy/archive/refs/tags/v$$SCRCPY_VERSION.zip && \
28 | unzip scrcpy.zip && find src -name "*.java" -exec cp -v {} scrcpy-$$SCRCPY_VERSION/server/{} \; && \
29 | cd scrcpy-$$SCRCPY_VERSION && \
30 | meson setup x --buildtype=release --strip -Db_lto=true -Dcompile_app=false -Dcompile_server=true && \
31 | sed -ibak 's/exit/echo/g' server/scripts/build-wrapper.sh && \
32 | ninja -Cx -v && \
33 | find . -type f -name "scrcpy-server" -exec cp -v {} .. \;
34 |
--------------------------------------------------------------------------------
/porting/src/controller-porting.c:
--------------------------------------------------------------------------------
1 | //
2 | // controller-porting.c
3 | // scrcpy-mobile
4 | //
5 | // Created by Ethan on 2022/6/2.
6 | //
7 |
8 | #define sc_controller_push_msg(...) sc_controller_push_msg_hijack(__VA_ARGS__)
9 |
10 | #include "controller.c"
11 |
12 | #undef sc_controller_push_msg
13 |
14 | // Defined in screen-porting.m
15 | #import "screen.h"
16 | struct sc_screen *
17 | sc_screen_current_screen(struct sc_screen *screen);
18 |
19 | // Fix negative point values and larger than screen size
20 | bool sc_controller_push_msg(struct sc_controller *controller,
21 | struct sc_control_msg *msg) {
22 | if (msg->type == SC_CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT) {
23 | // x/y is negative
24 | msg->inject_touch_event.position.point.x = msg->inject_touch_event.position.point.x < 0 ? 0 : msg->inject_touch_event.position.point.x;
25 | msg->inject_touch_event.position.point.y = msg->inject_touch_event.position.point.y < 0 ? 0 : msg->inject_touch_event.position.point.y;
26 |
27 | // x/y exceed max frame size
28 | struct sc_screen *screen = sc_screen_current_screen(NULL);
29 | if (screen != NULL) {
30 | struct sc_size screen_size;
31 | screen_size.width = screen->frame->width;
32 | screen_size.height = screen->frame->height;
33 |
34 | msg->inject_touch_event.position.point.x = msg->inject_touch_event.position.point.x > screen_size.width ? screen_size.width : msg->inject_touch_event.position.point.x;
35 | msg->inject_touch_event.position.point.y = msg->inject_touch_event.position.point.y > screen_size.height ? screen_size.height : msg->inject_touch_event.position.point.y;
36 | }
37 | }
38 |
39 | return sc_controller_push_msg_hijack(controller, msg);
40 | }
41 |
--------------------------------------------------------------------------------
/porting/src/display-porting.c:
--------------------------------------------------------------------------------
1 | //
2 | // screen-porting.c
3 | // scrcpy-module
4 | //
5 | // Created by Ethan on 2022/6/3.
6 | //
7 |
8 | #include "stdbool.h"
9 | #include
10 | #include
11 |
12 | bool ScrcpyEnableHardwareDecoding(void);
13 | int SDL_UpdateYUVTexture_hijack(SDL_Texture * texture,
14 | const SDL_Rect * rect,
15 | const Uint8 *Yplane, int Ypitch,
16 | const Uint8 *Uplane, int Upitch,
17 | const Uint8 *Vplane, int Vpitch);
18 | void SDL_RenderPresent_hijack(SDL_Renderer * renderer);
19 |
20 | #define SDL_UpdateYUVTexture(...) SDL_UpdateYUVTexture_hijack(__VA_ARGS__)
21 | #define SDL_RenderPresent(...) SDL_RenderPresent_hijack(__VA_ARGS__)
22 |
23 | #include "display.c"
24 |
25 | #undef SDL_UpdateYUVTexture
26 | #undef SDL_RenderPresent
27 |
28 | // Hijack SDL_UpdateYUVTexture
29 | int SDL_UpdateYUVTexture_hijack(SDL_Texture * texture,
30 | const SDL_Rect * rect,
31 | const Uint8 *Yplane, int Ypitch,
32 | const Uint8 *Uplane, int Upitch,
33 | const Uint8 *Vplane, int Vpitch)
34 | {
35 | if (ScrcpyEnableHardwareDecoding()) { return 0; }
36 | return SDL_UpdateYUVTexture(texture, rect, Yplane, Ypitch, Uplane, Upitch, Vplane, Vpitch);
37 | }
38 |
39 | void SDL_UpdateCommandGeneration(SDL_Renderer * renderer);
40 | void SDL_RenderPresent_hijack(SDL_Renderer * renderer) {
41 | if (ScrcpyEnableHardwareDecoding()) {
42 | // Update renderer_command_generation to fix memory leak when Destory_Texture
43 | SDL_UpdateCommandGeneration(renderer);
44 | return;
45 | }
46 | SDL_RenderPresent(renderer);
47 | }
48 |
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-vnc/VNCBrowserViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // VNCBrowserViewController.m
3 | // scrcpy-ios
4 | //
5 | // Created by Ethan on 2022/6/15.
6 | //
7 |
8 | #import "VNCBrowserViewController.h"
9 | #import "CVCreate.h"
10 | #import
11 |
12 | @interface VNCBrowserViewController ()
13 |
14 | @property (nonatomic, strong) WKWebView *webView;
15 |
16 | @end
17 |
18 | @implementation VNCBrowserViewController
19 |
20 | - (void)viewDidLoad {
21 | [super viewDidLoad];
22 | [self setupViews];
23 | [self loadVNCWithURL:[NSURL URLWithString:self.vncURL]];
24 | }
25 |
26 | -(void)setupViews {
27 | self.title = self.title.length > 0 ? self.title : @"Remote VNC";
28 | self.view.backgroundColor = UIColor.whiteColor;
29 |
30 | self.webView = [[WKWebView alloc] initWithFrame:(CGRectZero)];
31 | self.webView.navigationDelegate = (id)self;
32 | CVCreate.withView(self.webView).addToView(self.view)
33 | .centerXAnchor(self.view.centerXAnchor, 0)
34 | .centerYAnchor(self.view.centerYAnchor, 0)
35 | .widthAnchor(self.view.widthAnchor, 0)
36 | .heightAnchor(self.view.heightAnchor, 0);
37 |
38 | if (self.showsFullscreen) {
39 | [self.navigationController setNavigationBarHidden:YES animated:YES];
40 | CVCreate.UIImageView([UIImage imageNamed:@"disconnect"])
41 | .addToView(self.view)
42 | .backgroundColor(UIColor.grayColor)
43 | .cornerRadius(10)
44 | .rightAnchor(self.view.rightAnchor, -20)
45 | .topAnchor(self.view.topAnchor, 60)
46 | .click(self, @selector(disconnect));
47 | }
48 | }
49 |
50 | -(void)loadVNCWithURL:(NSURL *)url {
51 | [self.webView loadRequest:[NSURLRequest requestWithURL:url]];
52 | }
53 |
54 | -(void)disconnect {
55 | [self.navigationController popViewControllerAnimated:YES];
56 | }
57 |
58 | @end
59 |
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/LogManager.m:
--------------------------------------------------------------------------------
1 | //
2 | // LogManager.m
3 | // scrcpy-ios
4 | //
5 | // Created by Ethan on 2022/7/19.
6 | //
7 |
8 | #import "LogManager.h"
9 |
10 | #define kRecentLogsLimit 512*1024
11 |
12 | @interface LogManager ()
13 |
14 | @property (nonatomic, copy) NSString *logPath;
15 |
16 | @end
17 |
18 | @implementation LogManager
19 |
20 | +(instancetype)sharedManager {
21 | static LogManager *mananger = nil;
22 | static dispatch_once_t onceToken;
23 | dispatch_once(&onceToken, ^{
24 | mananger = [[LogManager alloc] init];
25 | });
26 | return mananger;
27 | }
28 |
29 | -(NSString *)logPath {
30 | return _logPath ?: ({
31 | NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
32 | [formatter setDateFormat:@"yyyy-MM"];
33 | NSString *dateString = [formatter stringFromDate:[NSDate date]];
34 | NSArray *allPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
35 | NSString *documentsDirectory = [allPaths objectAtIndex:0];
36 | NSString *logName = [NSString stringWithFormat:@"scrcpy@%@", dateString];
37 | _logPath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.log", logName]];
38 | });
39 | }
40 |
41 | -(void)startHandleLog {
42 | freopen([self.logPath cStringUsingEncoding:NSASCIIStringEncoding],"a+",stderr);
43 | freopen([self.logPath cStringUsingEncoding:NSASCIIStringEncoding],"a+",stdout);
44 | }
45 |
46 | -(NSString *)recentLogs {
47 | NSFileHandle *logHandle = [NSFileHandle fileHandleForReadingAtPath:self.logPath];
48 | NSDictionary *attrs = [NSFileManager.defaultManager attributesOfItemAtPath:self.logPath error:nil];
49 | NSInteger fileSize = [attrs[NSFileSize] integerValue];
50 | NSLog(@"LogPath: %@, Size: %@", self.logPath, @(fileSize));
51 | if (fileSize > kRecentLogsLimit) {
52 | [logHandle seekToFileOffset:fileSize-kRecentLogsLimit];
53 | }
54 | NSData *logData = [logHandle readDataOfLength:kRecentLogsLimit];
55 | return [[NSString alloc] initWithData:logData encoding:NSUTF8StringEncoding];
56 | }
57 |
58 | @end
59 |
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/porting/scripts/make-libsdl.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -x;
4 |
5 | OUTPUT=$(cd $OUTPUT && pwd);
6 | BUILD_DIR=$(mktemp -d -t SDL);
7 | cd $BUILD_DIR;
8 |
9 | curl -O https://www.libsdl.org/release/SDL2-2.0.22.tar.gz;
10 | tar xzvf SDL*.tar.gz;
11 |
12 | # Add Function SDL_UpdateCommandGeneration
13 | echo "=> Add Function SDL_UpdateCommandGeneration"
14 | echo "$(cat << EOF
15 | void
16 | SDL_UpdateCommandGeneration(SDL_Renderer *renderer) {
17 | renderer->render_command_generation++;
18 | }
19 | EOF
20 | )" >> SDL2-*/src/render/SDL_render.c;
21 |
22 | # Build iOS Libraries
23 | echo "=> Building for iOS..";
24 |
25 | xcodebuild clean build OTHER_CFLAGS="-fembed-bitcode" \
26 | BUILD_DIR=$BUILD_DIR/build \
27 | ARCHS="arm64" \
28 | CONFIGURATION=Debug \
29 | GCC_PREPROCESSOR_DEFINITIONS='CFRunLoopRunInMode=CFRunLoopRunInMode_fix' \
30 | -project SDL2-*/Xcode/SDL/SDL.xcodeproj -scheme "Static Library-iOS" -sdk iphoneos;
31 | xcodebuild clean build OTHER_CFLAGS="-fembed-bitcode" \
32 | BUILD_DIR=$BUILD_DIR/build \
33 | ARCHS="x86_64" \
34 | CONFIGURATION=Debug \
35 | GCC_PREPROCESSOR_DEFINITIONS='CFRunLoopRunInMode=CFRunLoopRunInMode_fix' \
36 | -project SDL2-*/Xcode/SDL/SDL.xcodeproj -scheme "Static Library-iOS" -sdk iphonesimulator;
37 |
38 | lipo -create build/*/libSDL2.a -output build/libSDL2.a;
39 | file build/libSDL2.a;
40 |
41 | [[ -d "$OUTPUT/include/SDL2" ]] || mkdir -pv $OUTPUT/include/SDL2;
42 | [[ -d "$OUTPUT/iphone" ]] || mkdir -pv $OUTPUT/iphone;
43 | [[ -d "$OUTPUT/iphone" ]] && {
44 | cp -v build/libSDL2.a $OUTPUT/iphone;
45 | cp -v SDL2-*/include/*.h $OUTPUT/include/SDL2;
46 | }
47 |
48 | # echo "=> Building for Android..";
49 |
50 | # # if mac arm64 host, run with x86_64 by arch command
51 | # ARCH_RUN="";
52 | # uname -m | grep arm64 && {
53 | # ARCH_RUN="arch -x86_64";
54 | # }
55 |
56 | # # Check android sdk home
57 | # [[ -z "$ANDROID_HOME" ]] && echo "No ANDROID_HOME set" && exit 1;
58 |
59 | # PATH=$PATH:$(dirname "$(find $ANDROID_HOME -name "ndk-build" | tail -n1)") $ARCH_RUN sh ./SDL2-*/build-scripts/androidbuildlibs.sh
60 | # [[ -d $OUTPUT/lib/android ]] || mkdir -pv $OUTPUT/lib/android/{arm64-v8a,armeabi-v7a,x86,x86_64};
61 |
62 | # cp -av SDL2-*/build/android/lib/arm64-v8a/* $OUTPUT/lib/android/arm64-v8a;
63 | # cp -av SDL2-*/build/android/lib/armeabi-v7a/* $OUTPUT/lib/android/armeabi-v7a;
64 | # cp -av SDL2-*/build/android/lib/x86/* $OUTPUT/lib/android/x86;
65 | # cp -av SDL2-*/build/android/lib/x86_64/* $OUTPUT/lib/android/x86_64;
66 |
67 | [[ -d "$BUILD_DIR" ]] && rm -rf $BUILD_DIR;
68 |
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/ScrcpyClient.h:
--------------------------------------------------------------------------------
1 | //
2 | // ScrcpyClient.h
3 | // scrcpy-ios
4 | //
5 | // Created by Ethan on 2022/6/2.
6 | //
7 |
8 | #import
9 | #import
10 | #import
11 |
12 | NS_ASSUME_NONNULL_BEGIN
13 |
14 | #define ScrcpySharedClient [ScrcpyClient sharedClient]
15 |
16 | @interface ScrcpyClient : NSObject
17 | // ADB Setup
18 | @property (nonatomic, assign) NSInteger adbDaemonPort;
19 | @property (nonatomic, copy) NSString *adbHomePath;
20 |
21 | // ADB Callbacks
22 | @property (nonatomic, copy) void (^onADBConnecting)(NSString *serial);
23 | @property (nonatomic, copy) void (^onADBConnected)(NSString *serial);
24 | @property (nonatomic, copy) void (^onADBUnauthorized)(NSString *serial);
25 | @property (nonatomic, copy) void (^onADBDisconnected)(NSString *serial);
26 | @property (nonatomic, copy) void (^onADBConnectFailed)(NSString *serial, NSString *message);
27 |
28 | // Scrcpy Callbacks
29 | @property (nonatomic, copy) void (^onScrcpyConnected)(NSString *serial);
30 | @property (nonatomic, copy) void (^onScrcpyConnectFailed)(NSString *serial);
31 | @property (nonatomic, copy) void (^onScrcpyDisconnected)(NSString *serial);
32 |
33 | // Pending URL Scheme
34 | @property (nonatomic, strong, nullable) NSURL *pendingScheme;
35 |
36 | // Switch Always Show Navigation Buttons
37 | @property (nonatomic, assign) BOOL shouldAlwaysShowNavButtons;
38 |
39 | // Switch to enable power saving mode on iPhone, with lower refresh rate and lower interactive response
40 | @property (nonatomic, assign) BOOL enablePowerSavingMode;
41 |
42 | // Shared instance
43 | +(instancetype)sharedClient;
44 |
45 | // ADB trace log
46 | -(void)enableADBVerbose;
47 |
48 | // Start ADB Server
49 | -(void)startADBServer;
50 |
51 | // Start scrcpy
52 | -(void)startWith:(NSString *)adbHost adbPort:(NSString *)adbPort options:(NSArray *)scrcpyOptions;
53 |
54 | // Stop scrcpy
55 | -(void)stopScrcpy;
56 |
57 | // Execute ADB commands
58 | -(BOOL)adbExecute:(NSArray *)commands message:(NSString *_Nullable*_Nullable)message;
59 |
60 | // Check pending scheme and start scrcpy
61 | -(void)checkStartScheme;
62 |
63 | // Default scrcpy options
64 | -(NSArray *)defaultScrcpyOptions;
65 |
66 | // Set scrcpy options
67 | -(NSArray *)setScrcpyOption:(NSArray *)options name:(NSString *)name value:(NSString *)value;
68 |
69 | // Send Home Button
70 | -(void)sendHomeButton;
71 |
72 | // Send Back Button
73 | -(void)sendBackButton;
74 |
75 | // Send SwitchApp Button
76 | -(void)sendSwitchAppButton;
77 |
78 | // Send Key Events
79 | -(void)sendKeycodeEvent:(SDL_Scancode)scancode keycode:(SDL_Keycode)keycode keymod:(SDL_Keymod)keymod;
80 |
81 | @end
82 |
83 | NS_ASSUME_NONNULL_END
84 |
--------------------------------------------------------------------------------
/porting/src/scrcpy-porting.c:
--------------------------------------------------------------------------------
1 | //
2 | // scrcpy-porting.c
3 | // scrcpy-mobile
4 | //
5 | // Created by Ethan on 2022/6/2.
6 | //
7 |
8 | #include "scrcpy-porting.h"
9 |
10 | #define sc_server_init(...) sc_server_init_hijack(__VA_ARGS__)
11 | #define sc_delay_buffer_init(...) sc_delay_buffer_init_hijack(__VA_ARGS__)
12 |
13 | #include "scrcpy.c"
14 |
15 | #undef sc_server_init
16 | #undef sc_delay_buffer_init
17 |
18 | __attribute__((weak))
19 | void ScrcpyUpdateStatus(enum ScrcpyStatus status) {
20 | printf("ScrcpyUpdateStatus: %d\n", status);
21 | }
22 |
23 | static void
24 | sc_server_on_connection_failed_hijack(struct sc_server *server, void *userdata) {
25 | sc_server_on_connection_failed(server, userdata);
26 |
27 | // Notify update status
28 | ScrcpyUpdateStatus(ScrcpyStatusConnectingFailed);
29 | }
30 |
31 | static void
32 | sc_server_on_disconnected_hijack(struct sc_server *server, void *userdata) {
33 | sc_server_on_disconnected(server, userdata);
34 |
35 | // Fixed here, send quit event
36 | SDL_Event event;
37 | event.type = SDL_QUIT;
38 | SDL_PushEvent(&event);
39 |
40 | // Notify update status
41 | ScrcpyUpdateStatus(ScrcpyStatusDisconnected);
42 | }
43 |
44 | static void
45 | sc_server_on_connected_hijack(struct sc_server *server, void *userdata) {
46 | sc_server_on_connected(server, userdata);
47 |
48 | // Notify update status
49 | ScrcpyUpdateStatus(ScrcpyStatusConnected);
50 | }
51 |
52 | // Handle sc_server_init to change cbs->on_disconnected callback
53 | // in order to quit normally when occur some unexpect network close like in sleep mode
54 | bool
55 | sc_server_init(struct sc_server *server, const struct sc_server_params *params,
56 | const struct sc_server_callbacks *cbs, void *cbs_userdata);
57 | bool
58 | sc_server_init_hijack(struct sc_server *server, const struct sc_server_params *params,
59 | const struct sc_server_callbacks *cbs, void *cbs_userdata) {
60 | static const struct sc_server_callbacks cbs_fixed = {
61 | .on_connection_failed = sc_server_on_connection_failed_hijack,
62 | .on_connected = sc_server_on_connected_hijack,
63 | .on_disconnected = sc_server_on_disconnected_hijack,
64 | };
65 | return sc_server_init(server, params, &cbs_fixed, cbs_userdata);
66 | }
67 |
68 | // Handle sc_delay_buffer_init to reset deley_buffer stopped status
69 | // this can fix the issue: cannot continue video and audio buffer after re-connect
70 | void
71 | sc_delay_buffer_init(struct sc_delay_buffer *db, sc_tick delay,
72 | bool first_frame_asap);
73 | void
74 | sc_delay_buffer_init_hijack(struct sc_delay_buffer *db, sc_tick delay,
75 | bool first_frame_asap) {
76 | sc_delay_buffer_init(db, delay, first_frame_asap);
77 | db->stopped = false;
78 | }
79 |
--------------------------------------------------------------------------------
/porting/src/screen-porting.c:
--------------------------------------------------------------------------------
1 | //
2 | // screen-porting.c
3 | // scrcpy-module
4 | //
5 | // Created by Ethan on 2022/6/3.
6 | //
7 |
8 | #include "stdbool.h"
9 |
10 | bool ScrcpyEnableHardwareDecoding(void);
11 |
12 | #define sc_screen_init(...) sc_screen_init_orig(__VA_ARGS__)
13 | #define sc_frame_buffer_consume(...) sc_frame_buffer_consume_hijack(__VA_ARGS__)
14 | #define sc_screen_handle_event(...) sc_screen_handle_event_hijack(__VA_ARGS__)
15 |
16 | #include "screen.c"
17 |
18 | #undef sc_screen_init
19 | #undef sc_frame_buffer_consume
20 | #undef sc_screen_handle_event
21 |
22 | struct sc_screen *
23 | sc_screen_current_screen(struct sc_screen *screen) {
24 | static struct sc_screen *current_screen;
25 | if (screen != NULL) {
26 | current_screen = screen;
27 | }
28 | return current_screen;
29 | }
30 |
31 | __attribute__((weak))
32 | float screen_scale(void) {
33 | return 2.f;
34 | }
35 |
36 | bool
37 | sc_screen_init(struct sc_screen *screen,
38 | const struct sc_screen_params *params) {
39 | bool ret = sc_screen_init_orig(screen, params);
40 |
41 | // Set renderer scale
42 | SDL_RenderSetScale(screen->display.renderer, screen_scale(), screen_scale());
43 |
44 | // Save current screen pointer
45 | sc_screen_current_screen(screen);
46 |
47 | return ret;
48 | }
49 |
50 | __attribute__((weak))
51 | void ScrcpyHandleFrame(AVFrame *frame) {}
52 |
53 | void
54 | sc_frame_buffer_consume(struct sc_frame_buffer *fb, AVFrame *dst);
55 | // Hijack sc_video_buffer_consume to convert NV12 pixels
56 | void
57 | sc_frame_buffer_consume_hijack(struct sc_frame_buffer *fb, AVFrame *dst) {
58 | sc_frame_buffer_consume(fb, dst);
59 |
60 | // Handle hardware frame render
61 | if (ScrcpyEnableHardwareDecoding()) ScrcpyHandleFrame(dst);
62 | }
63 |
64 | bool
65 | sc_screen_handle_event(struct sc_screen *screen, SDL_Event *event) {
66 | // Handle Clipboard Event to Sync Clipboard to Remote
67 | if (event->type == SDL_CLIPBOARDUPDATE) {
68 | char *text = SDL_GetClipboardText();
69 | if (!text) {
70 | LOGW("Could not get clipboard text: %s", SDL_GetError());
71 | return false;
72 | }
73 |
74 | char *text_dup = strdup(text);
75 | SDL_free(text);
76 | if (!text_dup) {
77 | LOGW("Could not strdup input text");
78 | return false;
79 | }
80 |
81 | struct sc_control_msg msg;
82 | msg.type = SC_CONTROL_MSG_TYPE_SET_CLIPBOARD;
83 | msg.set_clipboard.sequence = SC_SEQUENCE_INVALID;
84 | msg.set_clipboard.text = text_dup;
85 | msg.set_clipboard.paste = false;
86 |
87 | if (!sc_controller_push_msg(screen->im.controller, &msg)) {
88 | free(text_dup);
89 | LOGW("Could not request 'set device clipboard'");
90 | return false;
91 | }
92 | return true;
93 | }
94 |
95 | return sc_screen_handle_event_hijack(screen, event);
96 | }
97 |
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {"images":[{"size":"60x60","expected-size":"180","filename":"180.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"40x40","expected-size":"80","filename":"80.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"40x40","expected-size":"120","filename":"120.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"60x60","expected-size":"120","filename":"120.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"57x57","expected-size":"57","filename":"57.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"1x"},{"size":"29x29","expected-size":"58","filename":"58.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"29x29","expected-size":"29","filename":"29.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"1x"},{"size":"29x29","expected-size":"87","filename":"87.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"57x57","expected-size":"114","filename":"114.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"20x20","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"20x20","expected-size":"60","filename":"60.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"1024x1024","filename":"1024.png","expected-size":"1024","idiom":"ios-marketing","folder":"Assets.xcassets/AppIcon.appiconset/","scale":"1x"},{"size":"40x40","expected-size":"80","filename":"80.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"72x72","expected-size":"72","filename":"72.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"76x76","expected-size":"152","filename":"152.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"50x50","expected-size":"100","filename":"100.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"29x29","expected-size":"58","filename":"58.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"76x76","expected-size":"76","filename":"76.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"29x29","expected-size":"29","filename":"29.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"50x50","expected-size":"50","filename":"50.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"72x72","expected-size":"144","filename":"144.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"40x40","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"83.5x83.5","expected-size":"167","filename":"167.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"20x20","expected-size":"20","filename":"20.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"20x20","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"}]}
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/SDLUIKitDelegate+Extend.m:
--------------------------------------------------------------------------------
1 | //
2 | // SDLUIKitDelegate+Extend.m
3 | // scrcpy-ios
4 | //
5 | // Created by Ethan on 2022/6/11.
6 | //
7 |
8 | #import "SDLUIKitDelegate+Extend.h"
9 | #import "KFKeychain.h"
10 |
11 | @implementation SDLUIKitDelegate (Extend)
12 |
13 | -(void)applicationDidEnterBackground:(UIApplication *)application {
14 | NSTimeInterval beginBackgroundTime = [NSDate date].timeIntervalSince1970;
15 |
16 | // For more time execute in background
17 | static void (^beginTaskHandler)(void) = nil;
18 | beginTaskHandler = ^{
19 | __block UIBackgroundTaskIdentifier taskIdentifier = [UIApplication.sharedApplication beginBackgroundTaskWithName:@"com.mobile.scrcpy-ios.task" expirationHandler:^{
20 | [UIApplication.sharedApplication endBackgroundTask:taskIdentifier];
21 |
22 | if (NSDate.date.timeIntervalSince1970 - beginBackgroundTime < 60 * 2) {
23 | beginTaskHandler();
24 | }
25 | }];
26 | };
27 | beginTaskHandler();
28 | }
29 |
30 | -(BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary *)options
31 | {
32 | NSLog(@"> Received URL: %@", url.absoluteURL);
33 |
34 | // Handle Mode Switch URL
35 | if ([@[ScrcpySwitchModeCommand, ScrcpyModeADB, ScrcpyModeVNC] containsObject:url.host]) {
36 | [self switchScrcpyMode:url];
37 | return YES;
38 | }
39 |
40 | // Post connect
41 | [NSNotificationCenter.defaultCenter postNotificationName:ScrcpyConnectWithSchemeNotification object:nil userInfo:@{
42 | ScrcpyConnectWithSchemeURLKey : url
43 | }];
44 | return YES;
45 | }
46 |
47 | -(void)switchScrcpyMode:(NSURL *)switchURL {
48 | // URL likes scrcpy2://switch?mode=adb|vnc
49 | NSURLComponents *comps = [NSURLComponents componentsWithURL:switchURL resolvingAgainstBaseURL:NO];
50 | NSArray *modeItems = [comps.queryItems filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"SELF.name == %@", ScrcpySwitchModeKey]];
51 | if (modeItems.lastObject != nil) {
52 | NSURLQueryItem *modeItem = (NSURLQueryItem *)modeItems.lastObject;
53 | [self saveScrcpyMode:modeItem.value];
54 | return;
55 | }
56 |
57 | // URL likes scrcpy2://adb|vnc
58 | [self saveScrcpyMode:switchURL.host];
59 | }
60 |
61 | -(void)saveScrcpyMode:(NSString *)mode {
62 | [KFKeychain saveObject:mode forKey:ScrcpySwitchModeKey];
63 | NSLog(@"-> Scrcpy switched to %@ mode", mode);
64 |
65 | UIWindow *keyWindow = nil;
66 | for (UIWindow *window in UIApplication.sharedApplication.windows) {
67 | keyWindow = window.isKeyWindow ? window : keyWindow;
68 | }
69 |
70 | NSString *message = [NSString stringWithFormat:@"Scrcpy Remote is Switching to %@ Mode!", [mode uppercaseString]];
71 | UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Scrcpy"
72 | message:message
73 | preferredStyle:(UIAlertControllerStyleAlert)];
74 | [alert addAction:[UIAlertAction actionWithTitle:@"OK" style:(UIAlertActionStyleDefault) handler:^(UIAlertAction * _Nonnull action) {
75 | ScrcpyReloadViewController(keyWindow);
76 | }]];
77 |
78 | [keyWindow.rootViewController presentViewController:alert animated:YES completion:nil];
79 | }
80 |
81 | @end
82 |
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios.xcodeproj/xcshareddata/xcschemes/scrcpy-ios.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
44 |
46 |
52 |
53 |
54 |
55 |
59 |
60 |
61 |
62 |
68 |
70 |
76 |
77 |
78 |
79 |
81 |
82 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/LogsViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // LogsViewController.m
3 | // scrcpy-ios
4 | //
5 | // Created by Ethan on 2022/7/20.
6 | //
7 |
8 | #import "LogsViewController.h"
9 | #import "LogManager.h"
10 | #import "CVCreate.h"
11 | #import "UICommonUtils.h"
12 |
13 | @interface LogsViewController ()
14 | @property (nonatomic, weak) UITextView *logsView;
15 |
16 | @end
17 |
18 | @implementation LogsViewController
19 |
20 | #ifdef DEBUG
21 | +(void)reload {
22 | for (UIWindow *window in UIApplication.sharedApplication.windows) {
23 | if (window.rootViewController.presentedViewController) {
24 | [window.rootViewController.presentedViewController dismissViewControllerAnimated:YES completion:nil];
25 | }
26 | if ([window.rootViewController isKindOfClass:UINavigationController.class]) {
27 | LogsViewController *vc = [[LogsViewController alloc] initWithNibName:nil bundle:nil];
28 | UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:vc];
29 | [window.rootViewController presentViewController:nav animated:YES completion:nil];
30 | }
31 | }
32 | }
33 | #endif
34 |
35 | - (void)viewDidLoad {
36 | [super viewDidLoad];
37 | [self setupViews];
38 | }
39 |
40 | -(void)setupViews {
41 | self.title = @"Scrcpy Logs";
42 |
43 | SetupViewControllerAppearance(self);
44 |
45 | // Refresh Logs
46 | UIBarButtonItem *refreshItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"Refresh"]
47 | style:(UIBarButtonItemStylePlain)
48 | target:self
49 | action:@selector(refreshLogs)];
50 | refreshItem.tintColor = DynamicTintColor();
51 | UIBarButtonItem *shareItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"Share"]
52 | style:(UIBarButtonItemStylePlain)
53 | target:self
54 | action:@selector(shareLogs)];
55 | shareItem.tintColor = DynamicTintColor();
56 | self.navigationItem.rightBarButtonItem = refreshItem;
57 | self.navigationItem.leftBarButtonItem = shareItem;
58 |
59 | CVCreate.UITextView.fontSize(13)
60 | .textColor(DynamicTextColor())
61 | .text(LogManager.sharedManager.recentLogs)
62 | .addToView(self.view)
63 | .leftAnchor(self.view.leftAnchor, 5)
64 | .rightAnchor(self.view.rightAnchor, -5)
65 | .topAnchor(self.view.topAnchor, 5)
66 | .bottomAnchor(self.view.bottomAnchor, -5)
67 | .customView(^(UITextView *view) {
68 | self.logsView = view;
69 | view.editable = NO;
70 | });
71 |
72 | [self refreshLogs];
73 | }
74 |
75 | #pragma mark - Events
76 |
77 | -(void)refreshLogs {
78 | self.logsView.text = LogManager.sharedManager.recentLogs;
79 | [self.logsView scrollRangeToVisible:(NSRange){self.logsView.text.length-1, 1}];
80 | }
81 |
82 | -(void)shareLogs {
83 | NSArray *shareItems = @[ self.logsView.text ];
84 | UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:shareItems applicationActivities:nil];
85 | activityViewController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
86 | [self presentViewController:activityViewController animated:YES completion:nil];
87 | }
88 |
89 | @end
90 |
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/zh-Hans.lproj/Localizable.strings:
--------------------------------------------------------------------------------
1 | "ADB Host" = "ADB 主机地址";
2 | "ADB Port" = "ADB 主机端口";
3 | "ADB Port, Default 5555" = "ADB 主机端口,默认 5555";
4 | "--max-size, Default Unlimited" = "--max-size, 默认无限制";
5 | "--video-bit-rate, Default 4M" = "--video-bit-rate, 默认 4M";
6 | "--max-fps, Default 60" = "--max-fps, 默认 60";
7 | "Turn Screen Off:" = "连接后关闭物理屏幕:";
8 | "Stay Awake:" = "保持屏幕唤醒:";
9 | "Force ADB Forward:" = "强制使用 ADB Forward 模式:";
10 | "Turn Off When Closing:" = "断开连接后关闭屏幕:";
11 | "Always Show Navigation Buttons:" = "始终显示导航按键:";
12 | "Enable Audio(Android 11+):" = "开启音频(Android 11 以上):";
13 | "Power Saving Mode(for iPhone):" = "开启省电模式(iPhone 端):";
14 | "Connect" = "开始连接";
15 | "Copy URL Scheme" = "复制当前 URL Scheme";
16 | "For more help, please visit\nhttps://github.com/wsvn53/scrcpy-mobile" = "获取更多帮助,请访问\nhttps://github.com/wsvn53/scrcpy-mobile";
17 | "ADB\nConnecting" = "ADB\n连接中";
18 | "ADB\nConnected" = "ADB\n已连接成功";
19 | "ADB Connect Failed:\n%@" = "ADB 连接失败:\n%@";
20 | "Device [%@] connected, but unahtorized. Please accept authorization on your device." = "设备 %@ 已连接,但需要完成授权操作。请在设备后接受授权请求。";
21 | "Start Scrcpy Failed" = "启动 Scrcpy 失败";
22 | "Scrcpy\nConnected" = "Scrcpy\n已连接成功";
23 | "ADB Host is required" = "需要填写 ADB 主机地址";
24 | "Starting.." = "开始连接..";
25 | "Copied URL:\n%@" = "已复制 URL:\n%@";
26 | "Pair with [Pairing Code]" = "用 Pairing Code 匹配";
27 | "Show detailed scrcpy logs" = "显示 Scrcpy 详细日志";
28 | "Report an issue" = "报告问题/反馈";
29 | "Cancel" = "取消";
30 | "Switch Mode" = "切换连接模式";
31 | "Switching to VNC Mode?" = "是否切换到 VNC 模式?";
32 | "Yes, Switch VNC Mode" = "是,切换至 VNC 模式";
33 | "No, Continue ADB Mode" = "否,继续在 ADB 模式";
34 | "ADB Pair With Android" = "匹配到 Android 设备";
35 | "How To Pair With Android Devices:" = "如何匹配 Android 设备:";
36 | "1. Go to Settings -> System -> Developer Options\n2. Enable Wireless Debugging\n3. Pair device with pairing code" = "1. 前往【设置】->【系统】->【开发者选项】\n2. 开启无线调试\n3. 用匹配码匹配";
37 | "Note: This feature only available on Android 11 and above!" = "请注意,这个功能只在 Android 11 及以上可用。";
38 | "ADB Pairing IP Address" = "ADB 设备 IP 地址";
39 | "ADB Pairing Port" = "ADB 设备匹配端口";
40 | "ADB Pairing Code" = "ADB 匹配码";
41 | "Start Pairing" = "开始匹配";
42 | "Pairing Address is Empty!" = "匹配设备地址不能为空!";
43 | "Pairing Port is Empty" = "匹配端口不能为空!";
44 | "Pairing Code is Empty!" = "匹配码不能为空!";
45 | "Pairing.." = "匹配中..";
46 | "Scrcpy Remote VNC Client" = "Scrcpy Remote VNC 客户端";
47 | "VNC Host or ADB Host" = "VNC 地址或者 ADB 设备地址";
48 | "VNC Port or ADB Port" = "VNC 端口或者 ADB 端口";
49 | "VNC Password, Optional" = "VNC 密码,选填";
50 | "Auto Connect:" = "是否自动连接:";
51 | "View Only:" = "是否仅查看:";
52 | "Full Screen:" = "全屏模式:";
53 | "Scrcpy Remote currently only support VNC port over WebSocket. You can setup a websocket port by webcoskify https://github.com/novnc/websockify" = "Scrcpy Remote 当前仅支持基于 WebSocket 的 VNC 端口,你可以通过 websockify 设置一个 WebSocket 代理端口,具体可参考 https://github.com/novnc/websockify";
54 | "VNC Host is Required" = "VNC 地址不能为空!";
55 | "VNC Port is Required" = "VNC 端口不能为空!";
56 | "Switch ADB Mode" = "切换 ADB 模式";
57 | "Switching to ADB Mode?" = "是否切换到 ADB 模式?";
58 | "Yes, Switch ADB Mode" = "是,切换到 ADB 模式";
59 | "No, Continue VNC Mode" = "否,继续在 VNC 模式";
60 | "Import/Export ADB keys" = "导入/导出 ADB 密钥";
61 | "Export" = "导出";
62 | "ADB Private Key(adbkey):" = "ADB 私钥(adbkey):";
63 | "ADB Public Key(adbkey.pub):" = "ADB 公钥(adbkey.pub):";
64 | "Save Privatekey & Pubkey" = "保存 adbkey 私钥和公钥";
65 | "Import ADB Key Pair From File" = "从文件导入 ADB 密钥对";
66 | "Generate New ADB Key Pair" = "生成新的 ADB 密钥对";
67 | "Load ADB Key Failed: %@" = "加载 ADB 密钥失败:%@";
68 | "Load ADB PubKey Failed: %@" = "加载 ADB 公钥失败:%@";
69 | "New ADB key pair GENERATED.\nPlease RESTART the app for the new key pair to take effect." = "ADB key 生成成功。\n请重启 app 以使新的 ADB Key 生效。";
70 | "Save [adbkey] ERROR: %@" = "保存 adbkey 错误:%@";
71 | "Save [adbkey.pub] ERROR: %@" = "保存 adbkey.pub 错误:%@";
72 | "ADB Key Pairs Saved" = "ADB 密钥对已保存";
73 | "Please note that after regenerating the ADB key pairs, you may need to RE-AUTHORIZE on your remote phone." = "请注意:生成新的 ADB 密钥对后,你可能需要重新在远程设备上授权连接。";
74 | "Yes, Continue" = "继续生成";
75 | "No, Stop Generate" = "取消生成";
76 | "ADB Key has been MODIFIED but not saved, do you confirm to exit?" = "ADB 密钥对已修改但尚未保存,是否确认退出?";
77 | "ADB Key Pairs Exported" = "ADB 密钥对已导出";
78 | "ADB Key Pair Saved! Please restart app to take effect." = "ADB 密钥对保存成功!请重启 app 生效。";
79 |
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/SDL_uikitviewcontroller+Extend.m:
--------------------------------------------------------------------------------
1 | //
2 | // SDL_uikitviewcontroller+Extend.m
3 | // scrcpy-ios
4 | //
5 | // Created by Ethan on 2022/6/11.
6 | //
7 |
8 | #import "SDL_uikitviewcontroller+Extend.h"
9 | #import
10 | #import "CVCreate.h"
11 | #import "ScrcpyClient.h"
12 | #import "MenubarViewController.h"
13 |
14 | // ScrcpyMenubarGuideDidShow
15 | static NSString *ScrcpyMenubarGuideDidShow = @"ScrcpyMenubarGuideDidShow";
16 |
17 | @implementation SDL_uikitviewcontroller (Extend)
18 |
19 | // Checked that SDL_uikitviewcontroller not implemented viewDidLoad
20 | -(void)viewDidLoad {
21 | [super viewDidLoad];
22 | [self performSelector:@selector(addMenubarTriggerView) withObject:nil afterDelay:1.f];
23 | }
24 |
25 | -(void)showMenubarGuide {
26 | BOOL guideDidShow = [[NSUserDefaults standardUserDefaults] boolForKey:ScrcpyMenubarGuideDidShow];
27 | if (guideDidShow) {
28 | NSLog(@"Menubar guide has already shown.");
29 | return;
30 | }
31 |
32 | CVCreate.UIStackView(@[
33 | CVCreate.UIView,
34 | CVCreate.UIStackView(@[
35 | CVCreate.UIImageView([UIImage imageNamed:@"TouchIcon"])
36 | .size(CGSizeMake(30, 30))
37 | .customView(^(UIImageView *view){
38 | view.contentMode = UIViewContentModeCenter;
39 | }),
40 | CVCreate.UILabel.text(@"Long Press To Show Menu Bar")
41 | .boldFontSize(15.f)
42 | .textAlignment(NSTextAlignmentCenter)
43 | .textColor(UIColor.whiteColor),
44 | ]).spacing(10),
45 | CVCreate.UIView,
46 | ])
47 | .distribution(UIStackViewDistributionEqualSpacing)
48 | .addToView(self.view)
49 | .click(self, @selector(hideGuideView))
50 | .border(UIColor.whiteColor, 1.f)
51 | .backgroundColor([UIColor colorWithWhite:1 alpha:0.3])
52 | .topAnchor(self.view.bottomAnchor, -60)
53 | .bottomAnchor(self.view.bottomAnchor, 0)
54 | .leftAnchor(self.view.leftAnchor, 0)
55 | .rightAnchor(self.view.rightAnchor, 0)
56 | .customView(^(UIView *view){
57 | view.tag = @"GuideView".hash;
58 | });
59 | }
60 |
61 | -(void)hideGuideView {
62 | UIView *guideView = [self.view viewWithTag:@"GuideView".hash];
63 | [UIView animateWithDuration:0.3 animations:^{
64 | guideView.alpha = 0;
65 | } completion:^(BOOL finished) {
66 | // Mark as shown
67 | [NSUserDefaults.standardUserDefaults setBool:YES forKey:ScrcpyMenubarGuideDidShow];
68 |
69 | // Remove GuideView and Show Menubar
70 | [guideView removeFromSuperview];
71 | [self showMenubarView];
72 | }];
73 | }
74 |
75 | -(void)addMenubarTriggerView {
76 | if (self.viewLoaded == NO) {
77 | [self performSelector:@selector(addMenubarTriggerView) withObject:nil afterDelay:0.5];
78 | return;
79 | }
80 |
81 | CVCreate.UIView.addToView(self.view)
82 | .topAnchor(self.view.bottomAnchor, -60)
83 | .bottomAnchor(self.view.bottomAnchor, 0)
84 | .leftAnchor(self.view.leftAnchor, 0)
85 | .rightAnchor(self.view.rightAnchor, 0)
86 | .customView(^(UIView *view) {
87 | UILongPressGestureRecognizer *menuGesture = [[UILongPressGestureRecognizer alloc]
88 | initWithTarget:self
89 | action:@selector(onLongPress:)];
90 | menuGesture.minimumPressDuration = 0.5f;
91 | [view addGestureRecognizer:menuGesture];
92 | });
93 |
94 | // Check Always Show Navigation Buttons Setting
95 | if (ScrcpySharedClient.shouldAlwaysShowNavButtons) {
96 | [self showMenubarView];
97 | } else {
98 | [self showMenubarGuide];
99 | }
100 | }
101 |
102 | -(void)onLongPress:(UITapGestureRecognizer *)gesture {
103 | if (gesture.state == UIGestureRecognizerStateBegan) {
104 | [self showMenubarView];
105 | [self hideGuideView];
106 | }
107 | }
108 |
109 | -(void)showMenubarView {
110 | MenubarViewController *menuController = [[MenubarViewController alloc] initWithNibName:nil bundle:nil];
111 | menuController.modalPresentationStyle = UIModalPresentationCustom;
112 | [self presentViewController:menuController animated:YES completion:nil];
113 | }
114 |
115 | - (void)viewWillLayoutSubviews {
116 | [super viewWillLayoutSubviews];
117 | for (CALayer *layer in self.view.layer.sublayers) {
118 | if ([layer isKindOfClass:AVSampleBufferDisplayLayer.class]) {
119 | layer.frame = self.view.bounds;
120 | }
121 | }
122 | }
123 |
124 | @end
125 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # scrcpy-mobile
2 |
3 | Ported [scrcpy](https://github.com/Genymobile/scrcpy) for mobile platforms, to remotely control Android devices on your iPhone or Android phone.
4 |
5 | *Currently only supports controlling Android devices from iOS, Android controlling Android devices will be supported in future.*
6 |
7 | 
8 |
9 | ## Features
10 |
11 | * Supports scrcpy with ADB over WiFi ;
12 | * With Hardware decoding, less power and CPU comsumed;
13 | * Optimized gesture experiences for unstable network from mobile devices;
14 | * Supports start scrcpy from URL scheme;
15 | * Supports pair Android device with Pairing Code;
16 | * With Android navigation buttons: Back, Home, Switch App;
17 | * Supports toggle iOS keyboard and send keys to remote device;
18 | * Sync clipboard contents between iPhone and remote Android devices;
19 | * Support adbkey management: generate, modify, import, export;
20 | * Support audio forward to iPhone(for Android 11+ devices);
21 |
22 | ## Installation
23 |
24 | Scrcpy Mobile is now available on the App Store. You can download from:
25 |
26 | [](https://apps.apple.com/us/app/scrcpy-remote/id1629352527)
27 |
28 | ## Usage
29 |
30 | #### ADB Mode:
31 |
32 | After the App is installed, the default mode is VNC. You can switch to ADB WiFi mode by one of the following options:
33 |
34 | - **Option 1**: Visit this URL Scheme by click [scrcpy2://adb](scrcpy2://adb)
35 | - **Option 2**: Type the text `adb` in the **Host** textbox, then click **Connect**
36 | - **Option 3**: Type the text `5555` in the **Port** textbox, then click **Connect**
37 |
38 | And then please make sure that the Android devices has enabled the **adb tcpip** mode:
39 |
40 | ```sh
41 | adb tcpip 5555
42 | ```
43 |
44 | After authorized on your Android devices, scrcpy will continue to connect.
45 |
46 | **Or Pair with Pairing Code:**
47 |
48 | This only works on Android 10+ devices:
49 |
50 | - Click "..." menu icon on the top-left corner of Scrcpy Remote main window;
51 | - Click "Pair With Pairing Code";
52 | - Then on the Android device, go to:
53 | - `Settings` -> `System` -> `Developer Options` -> `Enable Wireless Debugging` -> `Pair device with pairing code`
54 |
55 | Then just follow the tips on Android device to start pair.
56 |
57 | #### VNC Mode:
58 |
59 | You can switch back to VNC mode by one of the following options:
60 |
61 | - **Option 1**: Visit the URL Scheme by click [scrcpy2://vnc](scrcpy2://vnc)
62 | - **Option 2**: Type the text `vnc` in the **Host** textbox, then click **Connect**
63 | - **Option 3**: Type the text `5900` in the **Port** textbox, then click **Connect**
64 |
65 | > Note: The VNC mode can only connect the VNC port that be proxied with websockify, and it's based on noVNC which is a web vnc client, so the performance and experience may not good.
66 |
67 | #### URL Scheme:
68 |
69 | After changed the options, you can click "Copy URL Scheme" to get the URL Scheme string, and you can create a shortcut in Shorcuts.app for connecting to scrcpy quickly.
70 |
71 | ```
72 | scrcpy2://example.com:5555?bit-rate=4M&max-size=1080
73 | ```
74 |
75 | #### Telegram Support:
76 |
77 | If you still have any question, you can join telegram channel:
78 |
79 | [](https://t.me/joinchat/I_HBlFpB27RkZTRl)
80 |
81 | ## Build
82 |
83 | Build all dependencies:
84 |
85 | ```sh
86 | make libs
87 | ```
88 |
89 | Build `scrcpy-server`:
90 |
91 | ```sh
92 | make -C porting scrcpy-server
93 | ```
94 |
95 | Then, Open `scrcpy-ios/scrcpy-ios.xcodeproj` to Build and Run.
96 |
97 | ## License
98 |
99 | ```
100 | MIT License
101 |
102 | Copyright (c) 2022 Ethan
103 |
104 | Permission is hereby granted, free of charge, to any person obtaining a copy
105 | of this software and associated documentation files (the "Software"), to deal
106 | in the Software without restriction, including without limitation the rights
107 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
108 | copies of the Software, and to permit persons to whom the Software is
109 | furnished to do so, subject to the following conditions:
110 |
111 | The above copyright notice and this permission notice shall be included in all
112 | copies or substantial portions of the Software.
113 |
114 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
115 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
116 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
117 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
118 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
119 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
120 | SOFTWARE.
121 | ```
122 |
123 |
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/UICommonUtils.h:
--------------------------------------------------------------------------------
1 | //
2 | // UICommonUtils.h
3 | // scrcpy-ios
4 | //
5 | // Created by Ethan on 26/2/23.
6 | //
7 |
8 | #ifndef UICommonUtils_h
9 | #define UICommonUtils_h
10 |
11 | #import
12 | #import "ScrcpySwitch.h"
13 |
14 | #define is_dark_mode (traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark)
15 |
16 | static inline UIColor *DynamicTintColor(void) {
17 | return [UIColor colorWithDynamicProvider:^UIColor * _Nonnull(UITraitCollection * _Nonnull traitCollection) {
18 | return is_dark_mode ? UIColor.whiteColor : UIColor.blackColor;
19 | }];
20 | }
21 |
22 | static inline UIColor *DynamicTextFieldBorderColor(void) {
23 | return [UIColor colorWithDynamicProvider:^UIColor * _Nonnull(UITraitCollection * _Nonnull traitCollection) {
24 | return is_dark_mode ? UIColor.whiteColor : [UIColor colorWithRed:0 green:0 blue:0 alpha:0.3];
25 | }];
26 | }
27 |
28 | static inline UIColor *DynamicTextColor(void) {
29 | return [UIColor colorWithDynamicProvider:^UIColor * _Nonnull(UITraitCollection * _Nonnull traitCollection) {
30 | return is_dark_mode ? UIColor.whiteColor : UIColor.darkGrayColor;
31 | }];
32 | }
33 |
34 | static inline UIColor *DynamicBackgroundColor(void) {
35 | return [UIColor colorWithDynamicProvider:^UIColor * _Nonnull(UITraitCollection * _Nonnull traitCollection) {
36 | return is_dark_mode ? UIColor.darkGrayColor : UIColor.whiteColor;
37 | }];
38 | }
39 |
40 | static inline NSAttributedString *DynamicColoredPlaceholder(NSString *text) {
41 | UIColor *dynamicColor = [UIColor colorWithDynamicProvider:^UIColor * _Nonnull(UITraitCollection * _Nonnull traitCollection) {
42 | return is_dark_mode ? UIColor.lightGrayColor : UIColor.grayColor;
43 | }];
44 | return [[NSAttributedString alloc] initWithString:text attributes:@{ NSForegroundColorAttributeName: dynamicColor}];
45 | }
46 |
47 | static inline void SetupViewControllerAppearance(UIViewController *vc) {
48 | // Enable dark mode
49 | vc.view.backgroundColor = [UIColor colorWithDynamicProvider:^UIColor * _Nonnull(UITraitCollection * _Nonnull traitCollection) {
50 | return (traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark) ? [UIColor colorWithRed:0.1 green:0.1 blue:0.1 alpha:1.0] : [UIColor whiteColor];
51 | }];
52 |
53 | if (@available(iOS 13.0, *)) {
54 | UINavigationBarAppearance *appearance = [[UINavigationBarAppearance alloc] init];
55 | [appearance configureWithOpaqueBackground];
56 | appearance.backgroundColor = [UIColor systemGray6Color];
57 | vc.navigationController.navigationBar.standardAppearance = appearance;
58 | vc.navigationController.navigationBar.scrollEdgeAppearance = appearance;
59 | }
60 | }
61 |
62 | static inline void ShowAlertFrom(UIViewController *fromController,
63 | NSString *message,
64 | UIAlertAction *okAction,
65 | UIAlertAction *cancelAction) {
66 | UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Scrcpy Remote" message:message preferredStyle:(UIAlertControllerStyleAlert)];
67 |
68 | if (okAction) [alert addAction:okAction];
69 | if (cancelAction) [alert addAction:cancelAction];
70 |
71 | if (!okAction && !cancelAction) {
72 | [alert addAction:[UIAlertAction actionWithTitle:@"OK" style:(UIAlertActionStyleCancel) handler:nil]];
73 | }
74 | [fromController presentViewController:alert animated:YES completion:nil];
75 | }
76 |
77 | static inline CVCreate *CreateDarkButton(NSString *title, id target, SEL action) {
78 | UIColor *borderColor = [UIColor colorWithDynamicProvider:^UIColor * _Nonnull(UITraitCollection * _Nonnull traitCollection) {
79 | return is_dark_mode ? UIColor.grayColor : UIColor.blackColor;
80 | }];
81 | return CVCreate.UIButton.text(title)
82 | .boldFontSize(16)
83 | .size(CGSizeMake(0, 45))
84 | .textColor(UIColor.whiteColor)
85 | .backgroundColor(UIColor.blackColor)
86 | .border(borderColor, 2.f)
87 | .cornerRadius(6)
88 | .click(target, action);
89 | }
90 |
91 | static inline CVCreate *CreateLightButton(NSString *title, id target, SEL action) {
92 | return CVCreate.UIButton.text(title)
93 | .boldFontSize(16)
94 | .size(CGSizeMake(0, 45))
95 | .textColor(UIColor.blackColor)
96 | .backgroundColor(UIColor.whiteColor)
97 | .border(UIColor.darkGrayColor, 2.f)
98 | .cornerRadius(6)
99 | .click(target, action);
100 | }
101 |
102 | static inline CVCreate *CreateScrcpySwitch(NSString *title, NSString *optionKey, void (^bindBlock)(ScrcpySwitch *view)) {
103 | return CVCreate.UIStackView(@[
104 | CVCreate.UILabel.text(title)
105 | .fontSize(16.f).textColor([UIColor colorWithDynamicProvider:^UIColor * _Nonnull(UITraitCollection * _Nonnull traitCollection) {
106 | return traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark ? UIColor.whiteColor : UIColor.blackColor;
107 | }]),
108 | CVCreate.create(ScrcpySwitch.class)
109 | .customView(^(ScrcpySwitch *view){
110 | view.optionKey = optionKey;
111 | bindBlock(view);
112 | }),
113 | ]).spacing(10.f);
114 | }
115 |
116 | #endif /* UICommonUtils_h */
117 |
--------------------------------------------------------------------------------
/porting/cmake/CMakeLists.txt:
--------------------------------------------------------------------------------
1 |
2 | cmake_minimum_required(VERSION 3.18.1)
3 |
4 | project("scrcpy")
5 |
6 | add_library( # Sets the name of the library.
7 | scrcpy
8 | # Sets the library as a shared library.
9 | STATIC
10 | # Sources of scrcpy
11 | ../../scrcpy/app/src/control_msg.c
12 |
13 | # Replace with porting version of cotnroller.c
14 | # ../../scrcpy/app/src/controller.c
15 | ../../porting/src/controller-porting.c
16 |
17 | ../../scrcpy/app/src/recorder.c
18 |
19 | # av_alloc_context has been moved to demuxer since v2.0
20 | # ../../scrcpy/app/src/demuxer.c
21 | ../../porting/src/demuxer-porting.c
22 |
23 | ../../scrcpy/app/src/cli.c
24 | ../../scrcpy/app/src/receiver.c
25 | ../../scrcpy/app/src/compat.c
26 | ../../scrcpy/app/src/mouse_inject.c
27 | ../../scrcpy/app/src/util/log.c
28 | ../../scrcpy/app/src/util/net_intr.c
29 | ../../scrcpy/app/src/util/thread.c
30 | ../../scrcpy/app/src/util/term.c
31 | ../../scrcpy/app/src/util/process.c
32 | ../../scrcpy/app/src/util/str.c
33 | ../../scrcpy/app/src/util/process_intr.c
34 | ../../scrcpy/app/src/util/strbuf.c
35 | ../../scrcpy/app/src/util/net.c
36 | ../../scrcpy/app/src/util/file.c
37 | ../../scrcpy/app/src/util/acksync.c
38 | ../../scrcpy/app/src/util/tick.c
39 | ../../scrcpy/app/src/util/intmap.c
40 | ../../scrcpy/app/src/util/intr.c
41 |
42 | # Replace with porting version of scrcpy.c
43 | # ../../scrcpy/app/src/scrcpy.c
44 | ../../porting/src/scrcpy-porting.c
45 |
46 | ../../scrcpy/app/src/v4l2_sink.c
47 |
48 | # Replace with porting version of screen.c
49 | # ../../scrcpy/app/src/screen.c
50 | ../../porting/src/screen-porting.c
51 |
52 | ../../scrcpy/app/src/fps_counter.c
53 | ../../scrcpy/app/src/clock.c
54 | ../../scrcpy/app/src/frame_buffer.c
55 | ../../scrcpy/app/src/server.c
56 | ../../scrcpy/app/src/keyboard_inject.c
57 | ../../scrcpy/app/src/file_pusher.c
58 |
59 | # Disable usb sources
60 | # ../../scrcpy/app/src/usb/usb.c
61 | # ../../scrcpy/app/src/usb/aoa_hid.c
62 | # ../../scrcpy/app/src/usb/screen_otg.c
63 | # ../../scrcpy/app/src/usb/hid_mouse.c
64 | # ../../scrcpy/app/src/usb/scrcpy_otg.c
65 | # ../../scrcpy/app/src/usb/hid_keyboard.c
66 |
67 | ../../scrcpy/app/src/adb/adb.c
68 | ../../scrcpy/app/src/adb/adb_device.c
69 | ../../scrcpy/app/src/adb/adb_tunnel.c
70 | ../../scrcpy/app/src/adb/adb_parser.c
71 |
72 | # Remove windows platform sources
73 | # ../../scrcpy/app/src/sys/win/process.c
74 | # ../../scrcpy/app/src/sys/win/file.c
75 |
76 | # Replace process.c to porting version
77 | # ../../scrcpy/app/src/sys/unix/process.c
78 | ../../porting/src/process-porting.c
79 | # Add process manager
80 | ../../porting/src/process-porting.cpp
81 | ../../scrcpy/app/src/sys/unix/file.c
82 |
83 | # Use porting main.c
84 | # ../../scrcpy/app/src/main.c
85 | ../../porting/src/main-porting.c
86 |
87 | ../../scrcpy/app/src/opengl.c
88 | ../../scrcpy/app/src/version.c
89 |
90 | # Replace decoder.c to porting version
91 | # ../../scrcpy/app/src/decoder.c
92 | ../../porting/src/decoder-porting.c
93 | ../../scrcpy/app/src/device_msg.c
94 | ../../scrcpy/app/src/input_manager.c
95 | ../../scrcpy/app/src/icon.c
96 | ../../scrcpy/app/src/options.c
97 |
98 | # Added from v2.0
99 | ../../porting/src/audio_player-porting.c
100 | ../../scrcpy/app/src/delay_buffer.c
101 | ../../scrcpy/app/src/packet_merger.c
102 | ../../scrcpy/app/src/util/memory.c
103 | ../../scrcpy/app/src/util/average.c
104 | ../../scrcpy/app/src/util/bytebuf.c
105 | ../../scrcpy/app/src/util/rand.c
106 | ../../scrcpy/app/src/trait/frame_source.c
107 | ../../scrcpy/app/src/trait/packet_source.c
108 |
109 | # Added from v2.2
110 | ../../porting/src/display-porting.c
111 | ../../scrcpy/app/src/util/timeout.c
112 | )
113 |
114 | target_include_directories(
115 | scrcpy
116 | PRIVATE
117 | .
118 | ../include
119 | ../../scrcpy/app/src
120 | ../../scrcpy/x/app
121 | ../../output/include
122 | ../../external/adb-mobile/output/include
123 | ../../external/adb-mobile/android-tools/vendor/boringssl/include
124 | )
125 |
126 | target_compile_options(
127 | scrcpy
128 | PRIVATE
129 | -include porting.h
130 | )
131 |
132 | target_link_options(scrcpy
133 | PRIVATE
134 | ../../output/iphone/libSDL2.a
135 | ../../output/iphone/libswscale.a
136 | ../../output/iphone/libswresample.a
137 | ../../output/iphone/libavutil.a
138 | ../../output/iphone/libavformat.a
139 | ../../output/iphone/libavfilter.a
140 | ../../output/iphone/libavdevice.a
141 | ../../output/iphone/libavcodec.a
142 | )
143 |
144 | set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "")
145 | set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++0x")
146 |
147 | #set_target_properties(scrcpy
148 | # PROPERTIES
149 | # STATIC_LIBRARY_FLAGS "../../output/iphone/libSDL2.a \
150 | # ../../output/iphone/libswscale.a \
151 | # ../../output/iphone/libswresample.a \
152 | # ../../output/iphone/libavutil.a \
153 | # ../../output/iphone/libavformat.a \
154 | # ../../output/iphone/libavfilter.a \
155 | # ../../output/iphone/libavdevice.a \
156 | # ../../output/iphone/libavcodec.a \
157 | # ")
158 |
--------------------------------------------------------------------------------
/scrcpy-ios/scrcpy-ios/MenubarViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // MenubarViewController.m
3 | // scrcpy-ios
4 | //
5 | // Created by Ethan on 2022/6/28.
6 | //
7 |
8 | #import "MenubarViewController.h"
9 | #import "CVCreate.h"
10 | #import "ScrcpyClient.h"
11 |
12 | @interface MenubarBackgroundView : UIView
13 | // Proxy touches to target SDL view
14 | @property (nonatomic, weak) UIView *targetSDLView;
15 |
16 | @end
17 |
18 | @implementation MenubarBackgroundView
19 |
20 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
21 | {
22 | for (UITouch *touch in touches) {
23 | if (touch.view != self) return;
24 | }
25 | [self.targetSDLView touchesBegan:touches withEvent:event];
26 | }
27 |
28 | - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
29 | {
30 | for (UITouch *touch in touches) {
31 | if (touch.view != self) return;
32 | }
33 | [self.targetSDLView touchesEnded:touches withEvent:event];
34 | }
35 |
36 | - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
37 | {
38 | for (UITouch *touch in touches) {
39 | if (touch.view != self) return;
40 | }
41 | [self.targetSDLView touchesCancelled:touches withEvent:event];
42 | }
43 |
44 | - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
45 | {
46 | for (UITouch *touch in touches) {
47 | if (touch.view != self) return;
48 | }
49 | [self.targetSDLView touchesMoved:touches withEvent:event];
50 | }
51 |
52 | @end
53 |
54 | @interface MenubarViewController ()
55 | @end
56 |
57 | @implementation MenubarViewController
58 |
59 | - (void)viewDidLoad {
60 | [super viewDidLoad];
61 | [self setupViews];
62 | }
63 |
64 | -(void)viewWillLayoutSubviews {
65 | [super viewWillLayoutSubviews];
66 | NSLog(@"self.view.frame = %@", NSStringFromCGRect(self.view.frame));
67 | }
68 |
69 | -(void)setupViews {
70 | self.view.backgroundColor = [UIColor clearColor];
71 | MenubarBackgroundView *backView = [[MenubarBackgroundView alloc] initWithFrame:(CGRectZero)];
72 | backView.targetSDLView = self.presentingViewController.view;
73 | CVCreate.withView(backView).addToView(self.view)
74 | .widthAnchor(self.view.widthAnchor, 0)
75 | .heightAnchor(self.view.heightAnchor, 0)
76 | .centerXAnchor(self.view.centerXAnchor, 0)
77 | .centerYAnchor(self.view.centerYAnchor, 0)
78 | .click(self, @selector(dismiss:));
79 |
80 | NSArray *(^CreateMenuItem)(NSString *, NSString *) = ^NSArray *(NSString *iconName, NSString *title) {
81 | return @[
82 | CVCreate.UIView.size(CGSizeMake(70, 10)),
83 | CVCreate.UIImageView([UIImage imageNamed:iconName])
84 | .customView(^(UIImageView *view){
85 | view.contentMode = UIViewContentModeCenter;
86 | }),
87 | CVCreate.UILabel.text(title).fontSize(13)
88 | .textColor(UIColor.whiteColor)
89 | .textAlignment(NSTextAlignmentCenter),
90 | CVCreate.UIView,
91 | ];
92 | };
93 |
94 | CVCreate.UIStackView(@[
95 | CVCreate.UIView,
96 | CVCreate.UIStackView(CreateMenuItem(@"BackIcon", NSLocalizedString(@"Back", nil))).axis(UILayoutConstraintAxisVertical)
97 | .click(self, @selector(sendBackButton:)),
98 | CVCreate.UIView,
99 | CVCreate.UIStackView(CreateMenuItem(@"HomeIcon", NSLocalizedString(@"Home", nil))).axis(UILayoutConstraintAxisVertical)
100 | .click(self, @selector(sendHomeButton:)),
101 | CVCreate.UIView,
102 | CVCreate.UIStackView(CreateMenuItem(@"SwitchAppIcon", @"Switch")).axis(UILayoutConstraintAxisVertical)
103 | .click(self, @selector(sendSwitchAppButton:)),
104 | CVCreate.UIView,
105 | CVCreate.UIStackView(CreateMenuItem(@"KeyboardIcon", @"Keyboard")).axis(UILayoutConstraintAxisVertical)
106 | .click(self, @selector(showKeyboard:)),
107 | CVCreate.UIView,
108 | CVCreate.UIStackView(CreateMenuItem(@"DisconnectIcon", @"Stop")).axis(UILayoutConstraintAxisVertical)
109 | .click(self, @selector(sendDisconnectButton:)),
110 | CVCreate.UIView,
111 | ]).axis(UILayoutConstraintAxisHorizontal)
112 | .distribution(UIStackViewDistributionEqualCentering)
113 | .backgroundColor([UIColor colorWithWhite:0 alpha:0.85])
114 | .size(CGSizeMake(0, 80))
115 | .addToView(backView)
116 | .click(self, @selector(doNothing))
117 | .centerXAnchor(backView.centerXAnchor, 0)
118 | .widthAnchor(backView.widthAnchor, 0)
119 | .bottomAnchor(backView.bottomAnchor, 0);
120 | }
121 |
122 | -(void)doNothing {}
123 |
124 | -(void)dismiss:(UITapGestureRecognizer *)gesture {
125 | SDL_StopTextInput();
126 |
127 | if (ScrcpySharedClient.shouldAlwaysShowNavButtons) {
128 | NSLog(@"Ignored dismiss, because of shouldAlwaysShowNavButtons has set to YES");
129 | return;
130 | }
131 |
132 | [self dismissViewControllerAnimated:YES completion:nil];
133 | }
134 |
135 | -(void)clickAnimated:(UITapGestureRecognizer *)tap {
136 | [UIView animateWithDuration:0.3 delay:0 options:0 animations:^{
137 | tap.view.backgroundColor = [UIColor colorWithWhite:0.3 alpha:0.5];
138 | } completion:^(BOOL finished) {
139 | tap.view.backgroundColor = UIColor.clearColor;
140 | }];
141 | }
142 |
143 | -(void)sendBackButton:(UITapGestureRecognizer *)tap {
144 | [self clickAnimated:tap];
145 | [ScrcpySharedClient sendBackButton];
146 | }
147 |
148 | -(void)sendHomeButton:(UITapGestureRecognizer *)tap {
149 | [self clickAnimated:tap];
150 | [ScrcpySharedClient sendHomeButton];
151 | }
152 |
153 | -(void)sendSwitchAppButton:(UITapGestureRecognizer *)tap {
154 | [self clickAnimated:tap];
155 | [ScrcpySharedClient sendSwitchAppButton];
156 | }
157 |
158 | -(void)showKeyboard:(UITapGestureRecognizer *)tap {
159 | NSLog(@"Showing keyboard");
160 | SDL_StartTextInput();
161 | }
162 |
163 | -(void)sendDisconnectButton:(UITapGestureRecognizer *)tap {
164 | [self clickAnimated:tap];
165 | [ScrcpySharedClient stopScrcpy];
166 | }
167 |
168 | @end
169 |
--------------------------------------------------------------------------------
/porting/src/process-porting.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // process-porting.cpp
3 | // scrcpy-mobile
4 | //
5 | // Created by Ethan on 2022/3/19.
6 | //
7 |
8 | #include "process-porting.hpp"
9 |
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 |
16 | #include