2009-04-21 21 views

Trả lời

21

Sau khi bị từ chối gần đây từ Apple

Không sử dụng này. Apple hiện sử dụng một số bản vá sẽ từ chối ứng dụng của bạn ngay lập tức nếu nó sử dụng bất kỳ API riêng nào - mặc dù cần lưu ý ở đây rằng một số ứng dụng trên App Store đã sử dụng ứng dụng này và vẫn ở đó!

Cách duy nhất để thực hiện việc này là chuẩn bị sẵn sàng để phát AVAudioPlayer nhưng không phát ([player prepareToPlay]). Điều này dường như chăm sóc điều chỉnh âm lượng của ứng dụng theo các nút rocker.

Hiện không có cách nào khác được xuất bản để xử lý việc này.

XIN ĐỌC GHI CHÚ TRÊN

Vâng, Sử dụng MPVolumeView

MPVolumeView *volume = [[[MPVolumeView alloc] initWithFrame:CGRectMake(18.0, 340.0, 284.0, 23.0)] autorelease]; 
    [[self view] addSubview:volume]; 

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(volumeChanged:) 
             name:@"AVSystemController_SystemVolumeDidChangeNotification" 
             object:nil];  
    for (UIView *view in [volume subviews]){ 
    if ([[[view class] description] isEqualToString:@"MPVolumeSlider"]) { 
     volumeViewSlider = view; //volumeViewSlider is a UIView * object 
    } 
    } 
    [volumeViewSlider _updateVolumeFromAVSystemController]; 

-(IBAction)volumeChanged:(id)sender{ 
    [volumeViewSlider _updateVolumeFromAVSystemController]; 
} 

này sẽ cung cấp cho bạn một thanh trượt (giống như được sử dụng trong ipod) có giá trị sẽ thay đổi acc để thể tích của điện thoại

Bạn sẽ nhận được cảnh báo thời gian biên dịch rằng chế độ xem có thể không phản hồi _updateVolumeFromAVSystemControl, nhưng chỉ cần bỏ qua nó.

+0

yeah, tôi đã suy nghĩ về nghe VolumeChanged nhưng tôi tự hỏi nếu nó vẫn sẽ nhận được một tin nhắn khi không có VolumeChange thực tế xảy ra (ví dụ khối lượng là tối đa và tôi đang tăng nó)? – COTOHA

+0

bạn có thể thử mã trên thiết bị và xem liệu sự kiện có được nhận hay không. – lostInTransit

+2

Bạn không thể gửi ứng dụng có mã này, nó sử dụng API riêng tư. Đó là những gì cảnh báo thời gian biên dịch là về, và tiền tố gạch dưới là một giveaway quá. – duncanwilcox

1

Nếu bạn sẵn sàng nhúng vào API riêng tư, tôi có a patch to Wolf3d bổ sung chính xác chức năng bạn đang tìm kiếm. Nó sử dụng AVSystemController lớp tư nhân và một số phương pháp ẩn trên UIApplication

17

Nếu bạn chỉ muốn để có được các thông báo, tôi nghĩ rằng đó là như thế này:

Xin vui lòng sửa tôi nếu tôi sai, nhưng tôi không tin điều này sử dụng bất kỳ API nội bộ nào.

[[NSNotificationCenter defaultCenter] addObserver:self 
     selector:@selector(volumeChanged:) 
     name:@"AVSystemController_SystemVolumeDidChangeNotification" 
     object:nil]; 

chi tiết của sự kiện này đang ở đây: http://www.cocoadev.com/index.pl?AVSystemController

Các câu trả lời khác ở đây dường như được dựa trên hack này: http://blog.stormyprods.com/2008/09/proper-usage-of-mpvolumeview-class.html đó là một giải pháp cho sự lỗi bây giờ cố định.

Nhưng tôi chắc rằng nếu tất cả các bạn muốn làm là GET thông báo, và không SET khối lượng hệ thống, bạn chỉ có thể sử dụng trung tâm thông báo giống như với bất kỳ sự kiện khác !!

Được thông báo: kể từ khi Apple thêm hành động tăng âm lượng vào máy ảnh, thông báo này là không phải được đăng khi hiển thị UIImagePickerController.

+0

Xác nhận hoạt động cho iOS 7. Đây phải là câu trả lời được chấp nhận. –

+2

Được thông báo, thông báo này là * không * được gửi khi 'UIImagePickerController' (ví dụ: cho máy ảnh) hiển thị. –

+0

nếu được xác minh cần được chỉnh sửa vào câu trả lời của bạn. –

1

Okay,

Vì vậy, tôi thấy giải pháp của bạn và không biết chính xác liệu Apple sẽ từ chối hoặc chấp nhận sử dụng AVSystemController_SystemVolumeDidChangeNotification. Nhưng tôi có một công việc xung quanh.

Sử dụng UISlider của MPVolumeView đăng ký cho bất kỳ thay đổi về khối lượng bằng phần cứng iPhone như thế này

MPVolumeView *volumeView = [[MPVolumeView alloc] initWithFrame:CGRectZero]; 

for (UIView *view in [volumeView subviews]) { 
    if ([view.class.description isEqualToString:@"MPVolumeSlider"]){ 
     self.volume_slider = (UISlider*)view; 
     break; 
    } 
} 
[volumeView sizeToFit]; 
#THIS IS THE MAIN LINE. ADD YOUR CALLBACK TARGET HERE 
[self.volume_slider addTarget:self action:@selector(volumeListener:) forControlEvents:UIControlEventValueChanged]; 
[self addSubview:volumeView]; 
[volumeView setAlpha:0.0f]; 

-(void)volumeListener:(NSNotification*)notification { 
    #UPDATE YOUR UI ACCORDING OR DO WHATEVER YOU WANNA DO. 
    #YOU CAN ALSO GET THE SOUND STEP VALUE HERE FROM NOTIFICATION. 
} 

Hãy cho tôi biết nếu điều này giúp bất cứ ai.

+0

Nó đi vào hai lần lúc đầu, tôi không thể hiểu tại sao. – ondermerol

1

Cách dễ nhất và chức năng nhất để thực hiện điều này mà tôi đã tìm thấy trong nghiên cứu tất cả các nguồn được đề cập ở trên và trong các chủ đề khác là: JPSVolumeButtonHandler (Tôi không tham gia khác ngoài việc là người dùng). chịu trách nhiệm!)

EDIT: Phiên bản 1.0.2 có một số thay đổi/cải tiến đáng kể. Tôi sẽ để lại câu trả lời trước của tôi cho 1.0.1 dưới màn hình đầu tiên.

Tôi đặt lớp trình bao bọc mẫu mà bạn có thể triển khai dưới dạng hoặc sử dụng để tìm hiểu cách sử dụng thích hợp hy vọng của JPSVolumeButtonHandler trong một separate Github repository real quick here.

Đây là cách các wrapper có nghĩa là để được sử dụng (tôi sẽ thêm video này vào kho lưu trữ ngay sau khi tôi nhận được vào nó):

  1. lớp Các singleton có hai lá cờ: isInUseisOn. isInUse có nghĩa là được đặt trong một số loại cài đặt ứng dụng chung và nút bật tắt hỗ trợ nói chung. Vì vậy, bất kể giá trị nào khác trong lớp, nếu đây là false sẽ không có gì xảy ra khi người dùng nhấn nút âm lượng và thực hiện đảm bảo càng nhiều càng tốt để giữ cho mọi thứ sạch sẽ và không ảnh hưởng đến mức âm lượng hệ thống không cần thiết. (Đọc các vấn đề được đề cập trong README cho những gì có thể xảy ra, khi hỗ trợ nút được bật lần đầu tiên.) isOn có nghĩa là phải là true chính xác trong khoảng thời gian nút cần thiết. Bạn có thể bật và tắt nó bất kể giá trị hiện tại của isInUse.

  2. Trong bất cứ xem các bạn khởi tạo các hành động đó là nghĩa vụ xảy ra khi một nút âm lượng được ép, thiết lập các hành động như vậy:

    PhysicalButton.shared.action = {/ * làm điều gì đó * /}

Hành động có loại () -> Void. Cho đến khi bạn khởi tạo hành động, sẽ không có gì xảy ra. Chỉ là không có gì sẽ xảy ra. Chức năng phòng thủ này rất quan trọng đối với tôi vì chế độ xem sử dụng hỗ trợ nút âm lượng sẽ chỉ được tạo sau khi hỗ trợ nút được thiết lập.

Để xem mọi thứ đang hoạt động, bạn có thể download the app mà tôi đang sử dụng tính năng này thật nhanh chóng miễn phí. Các cài đặt thao tác "Hỗ trợ nút vật lý" nói chung. Chế độ xem Đồng hồ bấm giờ chính là chế độ thực sự chuyển nút xử lý khi vào chế độ xem và tắt để bật chế độ xem. Nếu bạn tìm thấy thời điểm đó, bạn cũng sẽ tìm thấy một lưu ý quan trọng có trong Cài đặt> Hướng dẫn sử dụng> Tùy chọn: Nút vật lý Hỗ trợ:

Trong bối cảnh đặc biệt, ứng dụng có thể không có cơ hội để đúng switch nút âm lượng xử lý bên ngoài chế độ xem Đồng hồ bấm giờ ...

Tôi sẽ thêm ghi chú đầy đủ vào Github README.md. Cảm thấy tự do để thích ứng và tái sử dụng nó, nếu nó có liên quan trong trường hợp của bạn.

Các trường hợp không thực sự là ngoại lệ và tôi chưa hoàn toàn tìm ra điều gì sai. Khi người dùng giết ứng dụng (hoặc bạn chỉ dừng ứng dụng của mình từ bên trong Xcode) trong khi các nút âm lượng được bật, hỗ trợ nút vật lý có thể không được xóa đúng cách khỏi hệ điều hành. Vì vậy, bạn có thể kết thúc với hai trường hợp xử lý nội bộ, chỉ một trong số đó bạn có quyền kiểm soát. Vì vậy, sau đó, mỗi lần nhấn nút sẽ dẫn đến hai hoặc thậm chí nhiều cuộc gọi hơn đến hành động thường xuyên. Wrapper của tôi có một số mã người giám hộ để ngăn chặn quá nhanh một lời gọi của nút. Nhưng đó chỉ là một giải pháp từng phần. Việc sửa chữa cần phải đi vào trình xử lý cơ bản, điều mà tôi đáng tiếc là vẫn còn quá ít hiểu để cố tự sửa chữa mọi thứ.


OLD, CHO 1.0.1:

Đặc biệt, quan tâm của tôi là trong một giải pháp Swift. Mã nằm trong Objective-C. Để lưu một người nào đó một số nghiên cứu, đây là tất cả tôi đã sử dụng Cocoapods (đối với núm vú cao su như tôi):

  1. Thêm pod 'JPSVolumeButtonHandler' đến podfile
  2. Run pod install trên dòng lệnh
  3. Thêm #import <JPSVolumeButtonHandler.h> đến tập tin tiêu đề cầu nối
  4. Thiết lập callbacks cho âm lượng lên và xuống nút như vậy:

    let volumeButtonHandler = JPSVolumeButtonHandler(
        upBlock: { 
         log.debug("Volume up button pressed...") 
         // Do something when the volume up button is pressed... 
        }, downBlock: { 
         log.debug("Volume down button pressed...") 
         // Do something else for volume down... 
        }) 
    

Vậy đó. Phần còn lại là tùy chọn.


Trong trường hợp của tôi, tôi muốn để cho phép đè nút vật lý đẩy với các nút trên màn hình ảo chỉ cho quan điểm lựa chọn, trong khi đảm bảo để chặn ít nhất các chức năng nút bình thường càng tốt (để người dùng có thể chạy nhạc trong nền và điều chỉnh âm lượng của nó trong phần còn lại của ứng dụng tốt). Tôi đã kết thúc với một lớp học chủ yếu là singleton như sau:

class OptionalButtonHandler { 

    static var sharedInstance: OptionalButtonHandler? 

    private var volumeButtonHandler: JPSVolumeButtonHandler? = nil 
    private let action:() ->() 

    var enabled: Bool { 
    set { 
     if !enabled && newValue { 
      // Switching from disabled to enabled... 
      assert(volumeButtonHandler == nil, "No leftover volume button handlers") 
      volumeButtonHandler = JPSVolumeButtonHandler(upBlock: { 
       log.debug("Volume up button pressed...") 
       self.action() 
       }, downBlock: { 
        log.debug("Volume down button pressed...") 
        self.action() 
      }) 
     } else if enabled && !newValue { 
      log.debug("Disabling physical button...") 
      // The other way around: Switching from enabled to disabled... 
      volumeButtonHandler = nil 
     } 
    } 
    get { return (volumeButtonHandler != nil) } 
    } 

    /// For one-time initialization of this otherwise singleton class. 
    static func initSharedInstance(action:() ->()) { 
     sharedInstance = OptionalButtonHandler(action: action) 
    } 

    private init(action:() ->()) { 
     self.action = action 
    } 
} 

Chỉ có một hành động phổ biến cho cả nút tăng âm lượng lên và xuống ở đây. initSharedInstance() là cần thiết vì hành động của tôi bao gồm các tham chiếu đến phần tử giao diện người dùng (chế độ xem) sẽ chỉ được thiết lập tại một số điểm phụ thuộc vào người dùng sau khi khởi chạy ứng dụng.

Một thời gian thiết lập như sau:

OptionalButtonHandler.initSharedInstance({ 
    // ...some UI action 
}) 

Bật/tắt một cách chọn lọc chỉ đơn giản như vậy:

OptionalButtonHandler.sharedInstance!.enabled = true // (false) 

(Chú ý rằng mã logic của tôi đảm bảo rằng .enabled không bao giờ truy cập trước initSharedInstance().)

Tôi đang chạy Xcode 7.3 và iOS 9.3.2 trên thiết bị kiểm tra (bắt buộc!).

Mong muốn tìm hiểu cách Apple cảm thấy về việc quá tải các nút âm lượng quý giá của họ. Ít nhất ứng dụng của tôi đảm bảo tối thiểu xâm lấn và việc sử dụng nút thực sự có ý nghĩa. Nó không phải là một ứng dụng máy ảnh, nhưng các ứng dụng có thể so sánh đã sử dụng các nút âm lượng vật lý trước đó (thậm chí ít độc đáo hơn).

+0

Đã thử điều này trên iOS 10.2 mới nhất và không hoạt động – ShayanK

+0

Tôi đã cập nhật câu trả lời thật nhanh (hoặc thực sự không nhanh như vậy). Hy vọng nó giúp. Tôi dành một chút thời gian với phiên bản mới 1.0.2 để mã của tôi hoạt động. Hãy cho tôi biết nơi giải thích thêm có thể hữu ích. – marco

Các vấn đề liên quan