| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335 |
- /*
- * Copyright 2017 Google
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- import UIKit
- import FirebaseMessaging
- enum Row: String {
- case apnsToken
- case apnsStatus
- case requestAPNSPermissions
- case fcmToken
- }
- enum PermissionsButtonTitle: String {
- case requestPermissions = "Request User Notifications"
- case noAPNS = "Cannot Request Permissions (No APNs)"
- case alreadyRequested = "Already Requested Permissions"
- case simulator = "Cannot Request Permissions (Simulator)"
- }
- class MessagingViewController: UIViewController {
- let tableView: UITableView
- var sections = [[Row]]()
- var sectionHeaderTitles = [String?]()
- var allowedNotificationTypes: [NotificationsControllerAllowedNotificationType]?
- // Cached rows by Row type. Since this is largely a fixed table view, we'll
- // keep track of our created cells and UI, rather than have all the logic
- required init?(coder aDecoder: NSCoder) {
- tableView = UITableView(frame: CGRect.zero, style: .grouped)
- tableView.rowHeight = UITableViewAutomaticDimension
- tableView.estimatedRowHeight = 44
- // Allow UI Controls within the table to be immediately responsive
- tableView.delaysContentTouches = false
- super.init(coder: aDecoder)
- tableView.dataSource = self
- tableView.delegate = self
- }
- override func loadView() {
- super.loadView()
- view = UIView(frame: CGRect.zero)
- view.addSubview(tableView)
- // Ensure that the tableView always is the size of the view
- tableView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
- }
- override func viewDidLoad() {
- super.viewDidLoad()
- let center = NotificationCenter.default
- center.addObserver(self,
- selector: #selector(onAPNSTokenReceived),
- name: APNSTokenReceivedNotification,
- object: nil)
- center.addObserver(self,
- selector: #selector(onUserNotificationSettingsChanged),
- name: UserNotificationsChangedNotification,
- object: nil)
- center.addObserver(self,
- selector: #selector(onFCMTokenRefreshed),
- name: Notification.Name.MessagingRegistrationTokenRefreshed,
- object: nil)
- updateAllowedNotificationTypes {
- self.resetTableContents()
- self.tableView.reloadData()
- }
- }
- func onAPNSTokenReceived() {
- // Reload the appropriate cells
- updateAllowedNotificationTypes {
- if let tokenPath = self.indexPathFor(.apnsToken),
- let statusPath = self.indexPathFor(.apnsStatus),
- let requestPath = self.indexPathFor(.requestAPNSPermissions) {
- self.updateIndexPaths(indexPaths: [tokenPath, statusPath, requestPath])
- }
- }
- }
- func onFCMTokenRefreshed() {
- if let indexPath = indexPathFor(.fcmToken) {
- updateIndexPaths(indexPaths: [indexPath])
- }
- }
- func onUserNotificationSettingsChanged() {
- updateAllowedNotificationTypes {
- if let statusPath = self.indexPathFor(.apnsStatus),
- let requestPath = self.indexPathFor(.requestAPNSPermissions) {
- self.updateIndexPaths(indexPaths: [statusPath, requestPath])
- }
- }
- }
- private func updateIndexPaths(indexPaths: [IndexPath]) {
- tableView.beginUpdates()
- tableView.reloadRows(at: indexPaths, with: .none)
- tableView.endUpdates()
- }
- fileprivate func updateAllowedNotificationTypes(_ completion: (() -> Void)?) {
- NotificationsController.shared.getAllowedNotificationTypes { types in
- self.allowedNotificationTypes = types
- self.updateRequestAPNSButton()
- completion?()
- }
- }
- fileprivate func updateRequestAPNSButton() {
- guard !Environment.isSimulator else {
- requestPermissionsButton.isEnabled = false
- requestPermissionsButton.setTitle(PermissionsButtonTitle.simulator.rawValue, for: .normal)
- return
- }
- guard let allowedTypes = allowedNotificationTypes else {
- requestPermissionsButton.isEnabled = false
- requestPermissionsButton.setTitle(PermissionsButtonTitle.noAPNS.rawValue, for: .normal)
- return
- }
- requestPermissionsButton.isEnabled =
- (allowedTypes.count == 1 && allowedTypes.first! == .silent)
- let title: PermissionsButtonTitle =
- (requestPermissionsButton.isEnabled ? .requestPermissions : .alreadyRequested)
- requestPermissionsButton.setTitle(title.rawValue, for: .normal)
- }
- // MARK: UI (Cells and Buttons) Defined as lazy properties
- lazy var apnsTableCell: UITableViewCell = {
- let cell = UITableViewCell(style: .subtitle, reuseIdentifier: Row.apnsToken.rawValue)
- cell.textLabel?.numberOfLines = 0
- cell.textLabel?.lineBreakMode = .byWordWrapping
- return cell
- }()
- lazy var apnsStatusTableCell: UITableViewCell = {
- let cell = UITableViewCell(style: UITableViewCellStyle.value1, reuseIdentifier: Row.apnsStatus.rawValue)
- cell.textLabel?.text = "Allowed:"
- cell.detailTextLabel?.numberOfLines = 0
- cell.detailTextLabel?.lineBreakMode = .byWordWrapping
- return cell
- }()
- lazy var requestPermissionsButton: UIButton = {
- let button = UIButton(type: .system)
- button.setTitle(PermissionsButtonTitle.requestPermissions.rawValue, for: .normal)
- button.setTitleColor(UIColor.gray, for: .highlighted)
- button.setTitleColor(UIColor.gray, for: .disabled)
- button.titleLabel?.font = UIFont.preferredFont(forTextStyle: .body)
- button.addTarget(self,
- action: #selector(onRequestUserNotificationsButtonTapped),
- for: .touchUpInside)
- return button
- }()
- lazy var apnsRequestPermissionsTableCell: UITableViewCell = {
- let cell = UITableViewCell(style: .default,
- reuseIdentifier: Row.requestAPNSPermissions.rawValue)
- cell.selectionStyle = .none
- cell.contentView.addSubview(self.requestPermissionsButton)
- self.requestPermissionsButton.frame = cell.contentView.bounds
- self.requestPermissionsButton.autoresizingMask = [.flexibleWidth, .flexibleHeight]
- return cell
- }()
- lazy var fcmTokenTableCell: UITableViewCell = {
- let cell = UITableViewCell(style: .subtitle, reuseIdentifier: Row.fcmToken.rawValue)
- cell.textLabel?.numberOfLines = 0
- cell.textLabel?.lineBreakMode = .byCharWrapping
- return cell
- }()
- }
- // MARK: - Configuring the table view and cells with information
- extension MessagingViewController {
- func resetTableContents() {
- sections.removeAll()
- sectionHeaderTitles.removeAll()
- // APNS
- let apnsSection: [Row] = [.apnsToken, .apnsStatus, .requestAPNSPermissions]
- sections.append(apnsSection)
- sectionHeaderTitles.append("APNs")
- // FCM
- let fcmSection: [Row] = [.fcmToken]
- sections.append(fcmSection)
- sectionHeaderTitles.append("FCM Token")
- }
- func indexPathFor(_ rowId: Row) -> IndexPath? {
- var sectionIndex = 0
- for section in sections {
- var rowIndex = 0
- for row in section {
- if row == rowId {
- return IndexPath(row: rowIndex, section: sectionIndex)
- }
- rowIndex += 1
- }
- sectionIndex += 1
- }
- return nil
- }
- func configureCell(_ cell: UITableViewCell, withAPNSToken apnsToken: Data?) {
- guard !Environment.isSimulator else {
- cell.textLabel?.text = "APNs notifications are not supported in the simulator."
- cell.detailTextLabel?.text = nil
- return
- }
- if let apnsToken = apnsToken {
- cell.textLabel?.text = apnsToken.hexByteString
- cell.detailTextLabel?.text = "Tap to Share"
- } else {
- cell.textLabel?.text = "None"
- cell.detailTextLabel?.text = nil
- }
- }
- func configureCellWithAPNSStatus(_ cell: UITableViewCell) {
- if let allowedNotificationTypes = allowedNotificationTypes {
- let displayableTypes: [String] = allowedNotificationTypes.map { $0.rawValue }
- cell.detailTextLabel?.text = displayableTypes.joined(separator: ", ")
- } else {
- cell.detailTextLabel?.text = "Retrieving..."
- }
- }
- func configureCell(_ cell: UITableViewCell, withFCMToken fcmToken: String?) {
- if let fcmToken = fcmToken {
- cell.textLabel?.text = fcmToken
- cell.detailTextLabel?.text = "Tap to Share"
- } else {
- cell.textLabel?.text = "None"
- cell.detailTextLabel?.text = nil
- }
- }
- }
- // MARK: - UITableViewDataSource
- extension MessagingViewController: UITableViewDataSource {
- func numberOfSections(in tableView: UITableView) -> Int {
- return sections.count
- }
- public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
- return sections[section].count
- }
- public func tableView(_ tableView: UITableView,
- cellForRowAt indexPath: IndexPath) -> UITableViewCell {
- let row = sections[indexPath.section][indexPath.row]
- let cell: UITableViewCell
- switch row {
- case .apnsToken:
- cell = apnsTableCell
- configureCell(cell, withAPNSToken: Messaging.messaging().apnsToken)
- case .apnsStatus:
- cell = apnsStatusTableCell
- configureCellWithAPNSStatus(cell)
- case .requestAPNSPermissions:
- cell = apnsRequestPermissionsTableCell
- case .fcmToken:
- cell = fcmTokenTableCell
- configureCell(cell, withFCMToken: Messaging.messaging().fcmToken)
- }
- return cell
- }
- func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
- return sectionHeaderTitles[section]
- }
- }
- // MARK: - UITableViewDelegate
- extension MessagingViewController: UITableViewDelegate {
- func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
- tableView.deselectRow(at: indexPath, animated: true)
- let row = sections[indexPath.section][indexPath.row]
- switch row {
- case .apnsToken:
- if let apnsToken = Messaging.messaging().apnsToken {
- showActivityViewControllerFor(sharedItem: apnsToken.hexByteString)
- }
- case .fcmToken:
- if let fcmToken = Messaging.messaging().fcmToken {
- showActivityViewControllerFor(sharedItem: fcmToken)
- }
- default: break
- }
- }
- }
- // MARK: - UI Controls
- extension MessagingViewController {
- func onRequestUserNotificationsButtonTapped(sender: UIButton) {
- NotificationsController.shared.registerForUserFacingNotificationsFor(UIApplication.shared)
- }
- }
- // MARK: - Activity View Controller
- extension MessagingViewController {
- func showActivityViewControllerFor(sharedItem: Any) {
- let activityViewController = UIActivityViewController(activityItems: [sharedItem],
- applicationActivities: nil)
- present(activityViewController, animated: true, completion: nil)
- }
- }
|