Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[core][av] fix error on new architecture mode #30030

Merged
merged 6 commits into from
Jun 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/expo-av/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
### 🐛 Bug fixes

- Fixed putting app to background stops non-mixable audio playback in other apps on iOS ([#20380](https://github.com/expo/expo/pull/20380) by [@de1acr0ix](https://github.com/de1acr0ix))
- [iOS] Fixed broken Video view on New Architecture mode. ([#30030](https://github.com/expo/expo/pull/30030) by [@kudo](https://github.com/kudo))

### 💡 Others

Expand Down
9 changes: 8 additions & 1 deletion packages/expo-av/ios/EXAV/EXAV.m
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@
#import <EXAV/EXVideoView.h>
#import <EXAV/EXAudioRecordingPermissionRequester.h>
#import <EXAV/EXAV+AudioSampleCallback.h>
#if __has_include(<EXAV/EXAV-Swift.h>)
#import <EXAV/EXAV-Swift.h>
#else
#import "EXAV-Swift.h"
#endif

NSString *const EXAudioRecordingOptionsIsMeteringEnabledKey = @"isMeteringEnabled";
NSString *const EXAudioRecordingOptionsKeepAudioActiveHintKey = @"keepAudioActiveHint";
Expand Down Expand Up @@ -495,10 +500,12 @@ - (void)_runBlock:(void (^)(EXVideoView *view))block
[[_expoModuleRegistry getModuleImplementingProtocol:@protocol(EXUIManager)] executeUIBlock:^(id view) {
if ([view isKindOfClass:[EXVideoView class]]) {
block(view);
} else if ([[[view subviews] firstObject] isKindOfClass:[EXVideoView class]]) {
block([[view subviews] firstObject]);
} else {
reject(@"E_VIDEO_TAGINCORRECT", [NSString stringWithFormat:@"Invalid view returned from registry, expecting EXVideo, got: %@", view], nil);
}
} forView:reactTag ofClass:[EXVideoView class]];
} forView:reactTag ofClass:[ExpoVideoView class]];
}

#pragma mark - Internal audio recording helper methods
Expand Down
9 changes: 8 additions & 1 deletion packages/expo-av/ios/EXAV/EXAVTV.m
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@
#import <EXAV/EXAVPlayerData.h>
#import <EXAV/EXVideoView.h>
#import <EXAV/EXAV+AudioSampleCallback.h>
#if __has_include(<EXAV/EXAV-Swift.h>)
#import <EXAV/EXAV-Swift.h>
#else
#import "EXAV-Swift.h"
#endif

NSString *const EXDidUpdatePlaybackStatusEventName = @"didUpdatePlaybackStatus";

Expand Down Expand Up @@ -413,10 +418,12 @@ - (void)_runBlock:(void (^)(EXVideoView *view))block
[[_expoModuleRegistry getModuleImplementingProtocol:@protocol(EXUIManager)] executeUIBlock:^(id view) {
if ([view isKindOfClass:[EXVideoView class]]) {
block(view);
} else if ([[[view subviews] firstObject] isKindOfClass:[EXVideoView class]]) {
block([[view subviews] firstObject]);
} else {
reject(@"E_VIDEO_TAGINCORRECT", [NSString stringWithFormat:@"Invalid view returned from registry, expecting EXVideo, got: %@", view], nil);
}
} forView:reactTag ofClass:[EXVideoView class]];
} forView:reactTag ofClass:[ExpoVideoView class]];
}

#pragma mark - Internal audio recording helper methods
Expand Down
85 changes: 85 additions & 0 deletions packages/expo-av/ios/EXAV/ExpoVideoView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// Copyright 2015-present 650 Industries. All rights reserved.

import ExpoModulesCore

public final class ExpoVideoView: ExpoView {
private(set) var contentView: EXVideoView

private let onLoadStart = EventDispatcher()
private let onLoad = EventDispatcher()
private let onError = EventDispatcher()
private let onStatusUpdate = EventDispatcher()
private let onReadyForDisplay = EventDispatcher()
private let onFullscreenUpdate = EventDispatcher()

required init(appContext: AppContext? = nil) {
guard let legacyModuleRegistry = appContext?.legacyModuleRegistry else {
fatalError("Unable to get the legacyModuleRegistry from appContext.")
}
guard let contentView = EXVideoView(moduleRegistry: legacyModuleRegistry) else {
fatalError("Unable to create EXVideoView.")
}
self.contentView = contentView
super.init(appContext: appContext)
self.addSubview(self.contentView)

contentView.onLoadStart = createEventBinding(onLoadStart)
contentView.onLoad = createEventBinding(onLoad)
contentView.onError = createEventBinding(onError)
contentView.onStatusUpdate = createEventBinding(onStatusUpdate)
contentView.onReadyForDisplay = createEventBinding(onReadyForDisplay)
contentView.onFullscreenUpdate = createEventBinding(onFullscreenUpdate)
}

public override func layoutSubviews() {
super.layoutSubviews()
self.contentView.frame = bounds
}

var status: [AnyHashable: Any] {
get {
return contentView.status
}
set {
contentView.status = newValue
}
}

var useNativeControls: Bool {
get {
return contentView.useNativeControls
}
set {
contentView.useNativeControls = newValue
}
}

var source: [AnyHashable: Any] {
get {
return contentView.source
}
set {
contentView.source = newValue
}
}

var nativeResizeMode: String {
get {
return contentView.nativeResizeMode
}
set {
contentView.nativeResizeMode = newValue
}
}

/**
Create a binding from `EventDispatcher` to `EXDirectEventBlock`.
*/
private func createEventBinding(_ target: EventDispatcher) -> EXDirectEventBlock {
return { body in
if let payload = body as? [String: Any] {
target(payload)
}
}
}
}
20 changes: 11 additions & 9 deletions packages/expo-av/ios/EXAV/Video/VideoViewModule.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ public final class VideoViewModule: Module {

AsyncFunction("setFullscreen") { (viewTag: Int, value: Bool, promise: Promise) in
self.runBlockForView(viewTag) { view in
view.setFullscreen(value, resolver: promise.resolver, rejecter: promise.legacyRejecter)
view.contentView.setFullscreen(value, resolver: promise.resolver, rejecter: promise.legacyRejecter)
}
}

View(EXVideoView.self) {
View(ExpoVideoView.self) {
Events(
"onStatusUpdate",
"onLoadStart",
Expand All @@ -30,31 +30,33 @@ public final class VideoViewModule: Module {
"onFullscreenUpdate"
)

Prop("status") { (view: EXVideoView, status: [String: Any]) in
Prop("status") { (view: ExpoVideoView, status: [String: Any]) in
view.status = status
}

Prop("useNativeControls") { (view: EXVideoView, useNativeControls: Bool) in
Prop("useNativeControls") { (view: ExpoVideoView, useNativeControls: Bool) in
view.useNativeControls = useNativeControls
}

Prop("source") { (view: EXVideoView, source: [String: Any]) in
Prop("source") { (view: ExpoVideoView, source: [String: Any]) in
view.source = source
}

Prop("resizeMode") { (view: EXVideoView, resizeMode: String) in
Prop("resizeMode") { (view: ExpoVideoView, resizeMode: String) in
view.nativeResizeMode = resizeMode
}
}
}

private func runBlockForView(_ tag: Int, _ block: @escaping (EXVideoView) -> Void) {
private func runBlockForView(_ tag: Int, _ block: @escaping (ExpoVideoView) -> Void) {
let uiManager: EXUIManager? = appContext?.legacyModule(implementing: EXUIManager.self)

uiManager?.executeUIBlock({ (view: Any) in
if let view = view as? EXVideoView {
if let view = view as? ExpoVideoView {
block(view)
}
}, forView: tag, of: EXVideoView.self)
},
forView: tag,
of: ExpoVideoView.self)
}
}
1 change: 1 addition & 0 deletions packages/expo-modules-core/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
- [Android] Reduce the number of global references to JSIContext. ([#29936](https://github.com/expo/expo/pull/29936) by [@lukmccall](https://github.com/lukmccall))
- Fixed `getPathPermissions` permission error for local path with spaces on iOS 16 and older. ([#29958](https://github.com/expo/expo/pull/29958) by [@kudo](https://github.com/kudo))
- Fixed `RCTTriggerReloadCommandListeners` not found build error on iOS. ([#30014](https://github.com/expo/expo/pull/30014) by [@kudo](https://github.com/kudo))
- [iOS] Fixed broken `addUIBlock` and `executeUIBlock` on New Architecture mode. ([#30030](https://github.com/expo/expo/pull/30030) by [@kudo](https://github.com/kudo))

### 💡 Others

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -292,12 +292,7 @@ - (void)addUIBlock:(void (^)(UIView *view))block forView:(id)viewId

dispatch_async(RCTGetUIManagerQueue(), ^{
[uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
#if RCT_NEW_ARCH_ENABLED
UIView<RCTComponentViewProtocol> *componentView = [uiManager viewForReactTag:(NSNumber *)viewId];
UIView *view = [(ExpoFabricViewObjC *)componentView contentView];
#else
UIView *view = [uiManager viewForReactTag:(NSNumber *)viewId];
#endif
block(view);
}];
});
Expand All @@ -309,12 +304,7 @@ - (void)executeUIBlock:(void (^)(UIView *view))block forView:(id)viewId

dispatch_async(RCTGetUIManagerQueue(), ^{
[uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
#if RCT_NEW_ARCH_ENABLED
UIView<RCTComponentViewProtocol> *componentView = [uiManager viewForReactTag:(NSNumber *)viewId];
UIView *view = [(ExpoFabricViewObjC *)componentView contentView];
#else
UIView *view = [uiManager viewForReactTag:(NSNumber *)viewId];
#endif
block(view);
}];
[uiManager setNeedsLayout];
Expand Down
Loading