Как получить доступ к MPVolumeView в моем приложении делегата applicationWillTerminate? - PullRequest
0 голосов
/ 05 января 2019

РЕДАКТИРОВАТЬ: Похоже, что не может быть ЛЮБОГО возможного способа, только после завершения приложения, установить громкость устройства обратно на уровень, который был при запуске приложения. Для меня это возможный недосмотр со стороны Apple. Почему Apple не хочет, чтобы мое приложение было хорошим лагерем, которое покидает их лагерь так, как они его нашли, должен быть способ, пожалуйста, помогите ... Я попытался получить ответ на этот более широкий вопрос с другой темой. но он был закрыт как дубликат, зайдите туда и проголосуйте, чтобы открыть его снова:)

Когда мое приложение завершает работу, я хочу вернуть системный том на тот же уровень, который был при запуске моего приложения (Изменить: и не изменять громкость, когда приложение входит в фоновый режим).

Я пытаюсь сделать это с MPVolumeView в качестве механизма для настройки громкости устройств. Из того, что я исследовал, кажется, что это единственный способ программно настроить громкость устройств. Если есть другой способ, предложите его.

Итак, когда я запускаю свое приложение, я сохраняю системный том как внешнюю переменную 'appStartVol' в моем AppDelegate.m.

Я позволяю пользователю изменять громкость во время использования приложения с MPVolumeView.

Затем я пытаюсь установить системный том обратно на appStartVol в файле appDelegate.m applicationWillTerminate. РЕДАКТИРОВАТЬ: applicationWillTerminate вызывается, когда пользователь отклоняет приложения из списка своих последних. Я делаю это все время и оставляю регулярно используемые приложения в центре внимания, поэтому мне не нужно пролистывать 9 страниц значков, чтобы найти их. Итак, в этой функции есть причина делать то, что я прошу.

Я использую этот подход для яркости экрана, но не могу сделать это для громкости.

У меня возникли проблемы, потому что я не могу получить доступ к своему раскадровке MPVolumeView в AppDelegate.m applicationWillTerminate, и я не могу заставить локальный MPVolumeView работать в AppDelegate.m applicationWillTerminate.

Если я использую уведомление UIApplicationWillTerminateNotification в моем контроллере представления, я все еще сталкиваюсь с теми же проблемами в событии уведомления, так как раскадровка MPVolumeView также кажется недоступной из этого события.

РЕДАКТИРОВАТЬ: Это причина того, что использование кода в applicationDidEnterBackground не соответствует моим потребностям: Я хочу, чтобы мои пользователи могли использовать мой музыкальный проигрыватель на том уровне, который они имеют вручную выбранный в моем приложении, даже когда они решают сфокусировать внимание на другом приложении. Я считаю, что это то, что пользователи, естественно, предположили бы, произойдет. Например, почему изменился бы объем, если я хочу использовать калькулятор? Я также хочу верить, что естественным предположением для пользователя будет то, что том должен вернуться к объему до приложения, если приложение будет закрыто. Использование applicationDidEnterBackground приведет к тому, что приложение перейдет к объему перед приложением, как при переходе приложения в фоновый режим, так и при его завершении, это недопустимо.

ПОПЫТКА 1: Вот мой код в моем приложении AppDelegate.mWillTerminate:

- (void)applicationWillTerminate:(UIApplication *)application {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
NSLog(@"=== App is terminating ===");
UIScreen.mainScreen.brightness = brightnessORG;
NSLog(@"=== Screen brightness back to pre-app level of %f ===", brightnessORG);

UISlider *volumeViewSlider;
for (UIView *view in [_mpVolumeViewParentView subviews]){
    if ([view.class.description isEqualToString:@"MPVolumeSlider"]){
        volumeViewSlider = (UISlider*)view;
        volumeViewSlider.value = appStartVol;
        break;
    }
}
}

ПОПЫТКА 1: Вот мой AppDelegate.h:

#import <UIKit/UIKit.h>
#import <MediaPlayer/MediaPlayer.h>

extern CGFloat brightnessORG;
extern float appStartVol;

@interface AppDelegate : UIResponder <UIApplicationDelegate>
{
    MPVolumeView *_mpVolumeViewParentView;
}

@property (strong, nonatomic) UIWindow *window;

@property (nonatomic, retain) IBOutlet MPVolumeView *mpVolumeViewParentView;

@end

Re. ПОПЫТКА 1: Хотя этот код выполняется без ошибок, он не устанавливает для тома значение appStartVol, поскольку в делегатах приложения нет представлений [_mpVolumeViewParentView subviews]. Я, очевидно, не обращаюсь к mpVolumeViewParentView, который находится в моей раскадровке.

ПОПЫТКА 2: Посмотрим, смогу ли я просто добавить локальный MPVolumeView в приложение AppDelegate.mWillTerminate:

- (void)applicationWillTerminate:(UIApplication *)application {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
NSLog(@"=== App is terminating ===");
UIScreen.mainScreen.brightness = brightnessORG;
NSLog(@"=== Screen brightness back to pre-app level of %f ===", brightnessORG);

MPVolumeView *volumeView = [ [MPVolumeView alloc] init];
UISlider *volumeViewSlider;
volumeViewSlider = (UISlider*)volumeView;
volumeViewSlider.value = appStartVol;
}

Re. Попытка 2: выполняется с ошибкой = 'Завершение приложения из-за необработанного исключения' NSInvalidArgumentException ', причина:' - [MPVolumeView setValue:]: нераспознанный селектор, отправленный экземпляру '

Но я пытался :), как вы можете видеть, я новичок в цели ...

Любая помощь будет оценена :) 1050 *

ПОПЫТКА 3: Попробуйте подпредставления в локальном MPVolumeView в applicationWillTerminate:

MPVolumeView *_mpVolumeViewParentView = [ [MPVolumeView alloc] init];
MPVolumeView *volumeView = [ [MPVolumeView alloc] init];
[_mpVolumeViewParentView addSubview:volumeView];
UISlider *volumeViewSlider;
for (UIView *view in [_mpVolumeViewParentView subviews]){
    if ([view.class.description isEqualToString:@"MPVolumeSlider"]){
        volumeViewSlider = (UISlider*)volumeView;
        volumeViewSlider.value = appStartVol;
        break;
    }
}

Re. Попытка 3: выполняется с ошибкой при инициализации цикла: «Завершение приложения из-за необработанного исключения« NSInvalidArgumentException », причина:« - [MPVolumeView setValue:]: нераспознанный селектор, отправленный экземпляру »

ПОПЫТКА 4: После добавления инфраструктуры AVfoundation в проект я добавил это в свой AppDelegate.m:

    #import <AVFoundation/AVFoundation.h>

И я поместил эти две строки в приложение AppDelegate.mWillTerminate:

    AVAudioPlayer* wavplayer = [[AVAudioPlayer alloc] init];
    wavplayer.volume = appStartVol;

Re. Попытка 4: выполняется с ошибкой в ​​'wavplayer.volume = appStartVol;': 'Поток 1: EXC_BAD_ACCESS (код = 1, адрес = 0x48)', штопать ......

1 Ответ

0 голосов
/ 05 января 2019

Сначала вы пытаетесь что-то, что, вероятно, не может работать - вы приводите MPVolumeView к UISlider, а затем пытаетесь использовать UISlider setValue: метод. Но ваш объект все еще MPVolumeView и поддерживает этот метод. Так что это не может работать не потому, что вы используете его в неправильном месте, но никогда не работает.

Также - appWillTerminate недостаточно, поскольку он вызывается только в одном конкретном случае. Если приложение сначала переходит в фоновый режим, а затем убивается - willTerminate никогда не вызывается.

Полагаю, вы пытались что-то вроде описанного здесь iOS 9: Как программно изменить громкость, не показывая всплывающее окно системной звуковой панели? - но вы должны просто сделать то же самое - найдите UISlider в пределах подпредставления, вместо того, чтобы привести все это к себе.

Edit:

@implementation AppDelegate
{
    MPVolumeView* mv;
    UISlider* slider;
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    return YES;
}

- (void)applicationDidEnterBackground:(UIApplication *)application {
    slider.value = 1;
}

- (void)applicationDidBecomeActive:(UIApplication *)application {
    mv = [MPVolumeView new];
    for (UIView *view in [mv subviews]){
        if ([view.class.description isEqualToString:@"MPVolumeSlider"]){
            slider = ((UISlider*)view);
            break;
        }
    }
}

@end

это пример кода, который я использовал. Использование in terminate, к сожалению, не сработало, так что это самое лучшее, что я вижу, что можно сделать (я также думаю, что это более правильный способ, чем использование terminate, так как он не всегда вызывается). Помните, что это может прекратить работу в любое время или даже быть отклонено при отправке в AppStore.

...