ios打包

This commit is contained in:
yuqucheng 2026-06-22 17:05:53 +08:00
parent cec4f941ec
commit ba393f5266
8 changed files with 226 additions and 105 deletions

View File

@ -1,81 +0,0 @@
#if UNITY_IOS
using UnityEditor;
using UnityEditor.Callbacks;
using System.IO;
using System.Diagnostics;
public class FirebaseIosPodfilePostProcessor
{
[PostProcessBuild(100)] // 优先级设为 100在其他后处理之后执行
public static void OnPostProcessBuild(BuildTarget target, string pathToBuiltProject)
{
if (target != BuildTarget.iOS) return;
string podfilePath = Path.Combine(pathToBuiltProject, "Podfile");
// 生成 Podfile
string podfileContent = @"source 'https://cdn.cocoapods.org/'
platform :ios, '15.0'
target 'UnityFramework' do
pod 'Firebase/Core', '12.4.0'
pod 'Firebase/Auth', '12.4.0'
pod 'Firebase/Database', '12.4.0'
pod 'Firebase/Messaging', '12.4.0'
end
target 'Unity-iPhone' do
end
use_frameworks! :linkage => :static
";
File.WriteAllText(podfilePath, podfileContent);
UnityEngine.Debug.Log("[FirebaseIosPostProcessor] Podfile 已生成: " + podfilePath);
// 尝试自动运行 pod install
TryRunPodInstall(pathToBuiltProject);
}
private static void TryRunPodInstall(string projectPath)
{
try
{
ProcessStartInfo startInfo = new ProcessStartInfo
{
FileName = "pod",
Arguments = "install",
WorkingDirectory = projectPath,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true
};
using (Process process = Process.Start(startInfo))
{
string stdout = process.StandardOutput.ReadToEnd();
string stderr = process.StandardError.ReadToEnd();
process.WaitForExit();
if (process.ExitCode == 0)
{
UnityEngine.Debug.Log("[FirebaseIosPostProcessor] pod install 成功");
}
else
{
UnityEngine.Debug.LogWarning("[FirebaseIosPostProcessor] pod install 失败:\n" + stderr);
UnityEngine.Debug.LogWarning("[FirebaseIosPostProcessor] 请手动在 " + projectPath + " 目录下执行 pod install");
}
}
}
catch (System.Exception e)
{
UnityEngine.Debug.LogWarning("[FirebaseIosPostProcessor] 未找到 CocoaPods请手动执行:\n" +
" 1. 安装 CocoaPods: sudo gem install cocoapods\n" +
" 2. cd " + projectPath + "\n" +
" 3. pod install\n" +
" 错误: " + e.Message);
}
}
}
#endif

View File

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 3865f2d3232564d5eac2422f14cdf6e3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -4,9 +4,6 @@ FirebaseApp iOS and Android Dependencies.
-->
<dependencies>
<remoteSwiftPackage url="https://github.com/firebase/firebase-ios-sdk.git" version="12.14.0">
<swiftPackage name="FirebaseCore" replacesPod="Firebase/Core"/>
</remoteSwiftPackage>
<iosPods>
<iosPod name="Firebase/Core" version="12.14.0" minTargetSdk="15.0">
</iosPod>

View File

@ -4,9 +4,6 @@ FirebaseAuth iOS and Android Dependencies.
-->
<dependencies>
<remoteSwiftPackage url="https://github.com/firebase/firebase-ios-sdk.git" version="12.14.0">
<swiftPackage name="FirebaseAuth" replacesPod="Firebase/Auth"/>
</remoteSwiftPackage>
<iosPods>
<iosPod name="Firebase/Auth" version="12.14.0" minTargetSdk="15.0">
</iosPod>

View File

@ -4,9 +4,6 @@ FirebaseDatabase iOS and Android Dependencies.
-->
<dependencies>
<remoteSwiftPackage url="https://github.com/firebase/firebase-ios-sdk.git" version="12.14.0">
<swiftPackage name="FirebaseDatabase" replacesPod="Firebase/Database"/>
</remoteSwiftPackage>
<iosPods>
<iosPod name="Firebase/Database" version="12.14.0" minTargetSdk="15.0">
</iosPod>

View File

@ -0,0 +1,190 @@
#import <AVFoundation/AVFoundation.h>
#import <UIKit/UIKit.h>
// ──── 前向声明 ────
static void presentQRScannerWithName(NSString *goName);
@interface QRScannerViewController : UIViewController <AVCaptureMetadataOutputObjectsDelegate>
@property (nonatomic, strong) AVCaptureSession *session;
@property (nonatomic, strong) AVCaptureVideoPreviewLayer *previewLayer;
@property (nonatomic, copy) NSString *gameObjectName;
@property (nonatomic, assign) BOOL hasScanned;
@end
@implementation QRScannerViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor blackColor];
self.session = [[AVCaptureSession alloc] init];
AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
if (!device) {
[self sendResultToUnity:@"ERROR:NO_CAMERA"];
return;
}
NSError *error = nil;
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error];
if (!input) {
[self sendResultToUnity:[NSString stringWithFormat:@"ERROR:CAMERA_INPUT:%@", error.localizedDescription]];
return;
}
[self.session addInput:input];
AVCaptureMetadataOutput *output = [[AVCaptureMetadataOutput alloc] init];
[self.session addOutput:output];
[output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
output.metadataObjectTypes = @[AVMetadataObjectTypeQRCode];
self.previewLayer = [AVCaptureVideoPreviewLayer layerWithSession:self.session];
self.previewLayer.frame = self.view.bounds;
self.previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
[self.view.layer addSublayer:self.previewLayer];
// 半透明遮罩 + 扫描框
CGFloat boxSize = self.view.bounds.size.width * 0.65;
CGRect boxRect = CGRectMake(
(self.view.bounds.size.width - boxSize) / 2,
(self.view.bounds.size.height - boxSize) / 2 - 60,
boxSize, boxSize
);
CAShapeLayer *mask = [CAShapeLayer layer];
UIBezierPath *fullPath = [UIBezierPath bezierPathWithRect:self.view.bounds];
[fullPath appendPath:[[UIBezierPath bezierPathWithRoundedRect:boxRect cornerRadius:4] bezierPathByReversingPath]];
mask.path = fullPath.CGPath;
mask.fillColor = [UIColor colorWithWhite:0 alpha:0.5].CGColor;
[self.view.layer addSublayer:mask];
CAShapeLayer *border = [CAShapeLayer layer];
border.path = [UIBezierPath bezierPathWithRoundedRect:boxRect cornerRadius:4].CGPath;
border.strokeColor = [UIColor greenColor].CGColor;
border.lineWidth = 2;
border.fillColor = UIColor.clearColor.CGColor;
[self.view.layer addSublayer:border];
UILabel *hint = [[UILabel alloc] init];
hint.text = @"将二维码放入框内,即可自动扫描";
hint.textColor = UIColor.whiteColor;
hint.font = [UIFont systemFontOfSize:14];
hint.textAlignment = NSTextAlignmentCenter;
hint.frame = CGRectMake(20, boxRect.origin.y + boxRect.size.height + 20,
self.view.bounds.size.width - 40, 30);
[self.view addSubview:hint];
UIButton *cancel = [UIButton buttonWithType:UIButtonTypeSystem];
[cancel setTitle:@"关闭" forState:UIControlStateNormal];
[cancel setTitleColor:UIColor.whiteColor forState:UIControlStateNormal];
cancel.titleLabel.font = [UIFont systemFontOfSize:17];
cancel.frame = CGRectMake(0, self.view.bounds.size.height - 100,
self.view.bounds.size.width, 50);
[cancel addTarget:self action:@selector(onCancel) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:cancel];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self.session startRunning];
});
}
- (void)onCancel {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self.session stopRunning];
});
[self dismissViewControllerAnimated:YES completion:^{
[self sendResultToUnity:@"CANCEL"];
}];
}
- (void)sendResultToUnity:(NSString *)result {
const char *go = [self.gameObjectName UTF8String];
const char *msg = [result UTF8String];
UnitySendMessage((char *)go, "OnScanResult", (char *)msg);
}
#pragma mark - AVCaptureMetadataOutputObjectsDelegate
- (void)captureOutput:(AVCaptureOutput *)output
didOutputMetadataObjects:(NSArray<__kindof AVMetadataObject *> *)metadataObjects
fromConnection:(AVCaptureConnection *)connection {
if (self.hasScanned) return;
if (metadataObjects.count == 0) return;
AVMetadataMachineReadableCodeObject *code = metadataObjects.firstObject;
if (![code isKindOfClass:[AVMetadataMachineReadableCodeObject class]]) return;
self.hasScanned = YES;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self.session stopRunning];
});
[self dismissViewControllerAnimated:YES completion:^{
[self sendResultToUnity:code.stringValue ?: @"ERROR:EMPTY_RESULT"];
}];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self.session stopRunning];
});
}
@end
// ──── C 函数实现 ────
static void presentQRScannerWithName(NSString *goName) {
dispatch_async(dispatch_get_main_queue(), ^{
UIViewController *rootVC = UnityGetGLViewController();
if (!rootVC) {
UnitySendMessage((char *)[goName UTF8String],
"OnScanResult",
"ERROR:NO_ROOT_VC");
return;
}
QRScannerViewController *scanner = [[QRScannerViewController alloc] init];
scanner.gameObjectName = goName;
scanner.modalPresentationStyle = UIModalPresentationFullScreen;
[rootVC presentViewController:scanner animated:YES completion:nil];
});
}
extern "C" {
void _StartScanIOS(const char *gameObjectName)
{
NSString *goName = [NSString stringWithUTF8String:gameObjectName];
dispatch_async(dispatch_get_main_queue(), ^{
AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
if (status == AVAuthorizationStatusNotDetermined) {
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
if (granted) {
presentQRScannerWithName(goName);
} else {
UnitySendMessage((char *)[goName UTF8String],
"OnScanResult",
"ERROR:PERMISSION_DENIED");
}
}];
return;
}
if (status == AVAuthorizationStatusAuthorized) {
presentQRScannerWithName(goName);
} else {
UnitySendMessage((char *)[goName UTF8String],
"OnScanResult",
"ERROR:PERMISSION_DENIED");
}
});
}
}

View File

@ -0,0 +1,33 @@
fileFormatVersion: 2
guid: 7adc8635ee20a497c8ff442ae14a56f7
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
- first:
iPhone: iOS
second:
enabled: 1
settings:
AddToEmbeddedBinaries: false
userData:
assetBundleName:
assetBundleVariant:

View File

@ -29,14 +29,13 @@ namespace Kill.UI.Pages
currentActivity.Call("startActivityForResult", intent, 0);
}
#elif UNITY_IOS
// iOS 需要写原生插件
_StartScanIOS();
#endif
_StartScanIOS(gameObject.name);
#endif
}
#if UNITY_IOS
[System.Runtime.InteropServices.DllImport("__Internal")]
private static extern void _StartScanIOS();
private static extern void _StartScanIOS(string gameObjectName);
#endif
/// <summary>