Posts

Post not yet marked as solved
0 Replies
204 Views
I am trying to do the tests form the terminal and xcpretty the output. Here is the command: xcodebuild -workspace bimb-authenticate-ios.xcworkspace -scheme bimb-authenticate-ios-afx -configuration Debug -destination 'platform=iOS Simulator,name=iPhone 14 Pro,OS=16.4' -enableCodeCoverage YES -derivedDataPath Build/ clean build test | xcpretty -c "--report" "html" "--output" "../Project_report.html" However, the tests are never run. The simulator is not even opened. Here's the last items of the xcbuild logs: ... *compiling, linting and linking logs* 2024-03-27 21:42:37.151 xcodebuild[84540:2237180] [MT] IDETestOperationsObserverDebug: 264.553 elapsed -- Testing started completed. 2024-03-27 21:42:37.152 xcodebuild[84540:2237180] [MT] IDETestOperationsObserverDebug: 0.001 sec, +0.001 sec -- start 2024-03-27 21:42:37.152 xcodebuild[84540:2237180] [MT] IDETestOperationsObserverDebug: 264.554 sec, +264.553 sec -- end ▸ Test Succeeded Can anybody help me? Thanks.
Posted Last updated
.
Post not yet marked as solved
0 Replies
227 Views
Hi, I'm experiencing a bug that only occur in iPhone X/XS that run iOS 16.2. I couldn't tap the push notification when the app is already active. I need to trigger a feature when the push notification is tapped. When the app is on the background, it worked. But when the app is already active / on the foreground, it didn't. I tried this on an iPhone 8 Plus running iOS 16.2.1 and iPhone 14 and iPhone XR running iOS 17.1.2, but this bug didn't occur (ie. the tap was working and I can call didReceiveResponse callback). Why does this happen? Can anybody help me? Thanks.
Posted Last updated
.
Post marked as solved
1 Replies
480 Views
Hi, Just a quick one. I am working with a client who doesn't share his team's credentials like certificates, mobile provisioning, etc. He even refused to add me as one of the developer in his Apple Dev account. So, I am creating a new scheme for me that will use my own personal team and app ID to build it. While the main app's original scheme is basically unusable since I don't have the credentials to build it. The client still needs it for his CI/CD though. Now, the app has a Notification Service extension that will share UserDefaults via App Group. When I try to create a container with the same group ID as his, it always failed. It seems like we can't use it because it has already been taken by the clent. How do I fix this so I can just change the scheme to switch between the client's and mine? Thanks.
Posted Last updated
.
Post not yet marked as solved
0 Replies
235 Views
Hi, I'm trying to create some targets of my project with the exact source code, Info.plist, build settings, build phases, extensions, copied files, tests, etc like this: I've also created some schemes so we can toggle the targets by picking the scheme like this: I've set all of these targets with the same value instead of getting it from their $TARGET, $PRODUCT_BUNDLE_ID, etc: Info plist file = bimb-authenticate-ios/Info.plist Project Module Name = bimb_authenticate_ios Bundle Display name = BIMBAuthenticator I've added the targets in the Podfile like so: Podfile But when I tried building it, I;ve got these "Multiple commands" errors: Can you tell me what I did wrong here? Thank you.
Posted Last updated
.
Post not yet marked as solved
0 Replies
439 Views
Hi, I've got this html text: "<style>* {font-size: 12pt !important;color: #000000 !important;font-family: Montserrat-Regular !important;}</style>Perform the following steps:<br><u>Option 1:</u><br><p>1) Upon receiving a push notification alert, tap on the push notification to launch BIMB Authenticator</p><p>2) Verify the transaction details and choose \"Approve\"</p><p>3) Complete</p><br><u>Option 2:</u><br><ol><p>1) If you didn’t receive push notification, you may launch BIMB Authenticator</p><p>2) Verify the transaction details and choose \"Approve\"</p><p>3) Complete</p>" And I'm trying to show this HTML text properly in a UILabel. This is my codes: String extension to map to NSAttributedString: extension String { func attributedStringFromHTML() -> NSAttributedString? { guard let data = "\(self)" .data(using: .utf8, allowLossyConversion: false) else { Log.error(category: .transaction, message: "Unable to decode data from html string: %@", self) return nil } let options: [NSAttributedString.DocumentReadingOptionKey: Any] = [ .documentType: NSAttributedString.DocumentType.html, .characterEncoding: String.Encoding.utf8.rawValue ] if let attributedString = try? NSAttributedString(data: data, options: options, documentAttributes: nil) { return attributedString } else { Log.error(category: .transaction, message: "Unable to create attributed string from html string: %@", self) return nil } } } And this is the result: Can you tell me how to fix this? Thanks.
Posted Last updated
.
Post marked as solved
1 Replies
420 Views
I have this ToastView that will animate by expanding the height from the top of the screen. All the components are created programmatically. This is the code: final class ToastView: UIView { private static let instance = createContainer() private let labelHeightOffset: CGFloat = 32 private let messageLabel: UILabel = { let label = UILabel() label.textAlignment = .center label.numberOfLines = 0 return label }() private var heightConstraint: NSLayoutConstraint! static func show(message: String) { let keyWindow = UIWindow.getKeyWindow() //extension to get the kley window show(on: keyWindow, message: message) } private static func show(on parentView: UIView? = nil, message: String) { guard let parentView = parentView ?? UIViewController.getTopViewController()?.view, instance.superview == nil, let toast = toast else { return } parentView.addSubview(instance, method: .fill) toast.messageLabel.text = message toast.messageLabel.textColor = .red toast.messageLabel.textAlignment = .center toast.messageLabel.sizeToFit() toast.show(for: 3) } private func show(for duration: TimeInterval = 0) { isHidden = false layoutIfNeeded() UIView.animate(withDuration: 0.4, animations: { let labelLineHeight = self.messageLabel.getRect(maxLine: 3).size.height //getRect is an extension func to get the rect based on the content of the label let lineSpaces = CGFloat((self.messageLabel.getLineNumber() - 1) * 2) //getLineNumber is an extension func to get the total number of lines based on the content //Get the height by the content of the label self.heightConstraint.constant = self.labelLineHeight + self.labelHeightOffset + lineSpaces self.setNeedsUpdateConstraints() self.superview?.layoutIfNeeded() }, completion: { _ in self.hide(delay: duration) }) } private func hide(delay: TimeInterval = 0) { UIView.animate(withDuration: 0.4, delay: delay, animations: { self.heightConstraint.constant = 0 self.setNeedsUpdateConstraints() self.superview?.layoutIfNeeded() }, completion: { _ in self.isHidden = true self.messageLabel.text = nil ToastView.instance.removeFromSuperview() }) } } private extension ToastView { static var toast: ToastView? { return instance.subviews[0] as? ToastView } static func createContainer() -> UIView { let container = UIView(frame: .zero) container.backgroundColor = .clear let toast = ToastView(frame: .zero) toast.backgroundColor = .white toast.addCorner(radius: 8) container.addSubview(toast) toast.layoutMessageLabel() toast.layoutToast() return container } func layoutMessageLabel() { addSubview(messageLabel) messageLabel.center = center messageLabel.translatesAutoresizingMaskIntoConstraints = false let constraints = [ centerYAnchor.constraint(equalTo: messageLabel.centerYAnchor), leftAnchor.constraint(equalTo: messageLabel.leftAnchor, constant: 16), rightAnchor.constraint(equalTo: messageLabel.rightAnchor, constant: 16) ] NSLayoutConstraint.activate(constraints) messageLabel.setNeedsUpdateConstraints() layoutIfNeeded() } func layoutToast() { translatesAutoresizingMaskIntoConstraints = false let topConstants: CGFloat = UIWindow.getKeyWindow()?.safeAreaInsets.top ?? 0 + 16 let topConstraint = topAnchor.constraint(equalTo: superview!.topAnchor, constant: topConstants) heightConstraint = heightAnchor.constraint(equalToConstant: 0) let constraints = [ topConstraint, heightConstraint!, leftAnchor.constraint(equalTo: superview!.leftAnchor, constant: 16), superview!.rightAnchor.constraint(equalTo: rightAnchor, constant: 16) ] NSLayoutConstraint.activate(constraints) setNeedsUpdateConstraints() superview!.layoutIfNeeded() } } The code is working fine EXCEPT for the first time it appears. It always animates from the bottom of the screen and rising above ot the top. But if you'll have a look at the code, I only animte the heightConstraint's constant value. Why is this happening? Can you help me fix this? thanks.
Posted Last updated
.
Post marked as solved
1 Replies
395 Views
I am trying to wrap os_log for logging in my iOS app like so: import Foundation import OSLog enum LogCategory: String, CaseIterable { case viewCycle case tracking case api } struct Log { private static let logs = { return LogCategory.allCases .reduce(into: [LogCategory: OSLog]()) { dict, category in dict[category] = OSLog(subsystem: Bundle.main.bundleIdentifier ?? "BIMB", category: category.rawValue) } }() static func debug(category: LogCategory, message: StaticString, _ args: CVarArg...) { logImpl(category: category, message: message, type: .debug, args) } static func info(category: LogCategory, message: StaticString, _ args: CVarArg...) { logImpl(category: category, message: message, type: .info, args) } static func notice(category: LogCategory, message: StaticString, _ args: CVarArg...) { logImpl(category: category, message: message, type: .default, args) } static func warning(category: LogCategory, message: StaticString, _ args: CVarArg...) { logImpl(category: category, message: message, type: .default, args) } static func error(category: LogCategory, message: StaticString, _ args: CVarArg...) { logImpl(category: category, message: message, type: .error, args) } static func critical(category: LogCategory, message: StaticString, _ args: CVarArg...) { logImpl(category: category, message: message, type: .fault, args) } private static func logImpl(category: LogCategory, message: StaticString, type: OSLogType, _ args: CVarArg...) { guard let log = logs[category] else { return } os_log(message, log: log, type: type, args) } } The problem is if I did this: Log.debug(category: .tracking, message: "Device ID: %s.", UIDevice.current.identifierForVendor?.uuidString ?? "unknown") it always crashed with this error: 2023-12-13 12:33:35.173798+0700 bimb-authenticate-ios[62740:928633] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Swift.__SwiftDeferredNSArray UTF8String]: unrecognized selector sent to instance 0x600000dcbbc0' But if I just do it with os_log like this: os_log("Device ID: %s.", log: OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "tracking"), type: .debug, UIDevice.current.identifierForVendor?.uuidString ?? "unknown") it worked fine. Also if I changed %@ in my wrapper instead, it didn't crash, but the idfv is shown inside a pair of brackets like this: Device ID: ( "C0F906C8-CD73-44F6-86A1-A587248680D3" ).` But with os_log it is shown normally like this: Device ID: C0F906C8-CD73-44F6-86A1-A587248680D3. Can you tell me what's wrong here? And how do I fix this? Thanks. NOTE: This is using os_log since the minimum version is iOS 11. I don't know why people advising me with using Logger instead.
Posted Last updated
.
Post not yet marked as solved
1 Replies
387 Views
Hi, I have a WKWebview to open the client's website. In the website, there is a "Cancel" button that will open a popup for confirmation. In Safari or other web clients, it works and it will open a popup. But in my iOS app, it didn't. When I ask the web FE developer, he said that he is using jQuery modal dialog for the popup. I tried using this, but doesn't work: class WebsiteViewController: UIViewController { var urlRequest: URLRequest? @IBOutlet weak private var ibWebView: WKWebView! override func viewDidLoad() { super.viewDidLoad() ibWebView.configuration.websiteDataStore = .nonPersistent() ibWebView.configuration.preferences.javaScriptEnabled = true ibWebView.configuration.preferences.javaScriptCanOpenWindowsAutomatically = true ibWebView.navigationDelegate = self ibWebView.uiDelegate = self loadInternetBanking() } private func loadInternetBanking() { guard let urlRequest = urlRequest else { return } ibWebView.load(urlRequest) } } extension InternetBankingViewController: WKUIDelegate { func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? { print(":::::::: createWebViewWith!!!!") //- this doesn't get called let popupWebView = WKWebView(frame: view.bounds, configuration: configuration) popupWebView.autoresizingMask = [.flexibleWidth, .flexibleHeight] return popupWebView } func webViewDidClose(_ webView: WKWebView) { } func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo) async { print(":::::::: runJavaScriptAlertPanelWithMessage!!!!") //- this doesn't get called } func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo) async -> Bool { print(":::::::: runJavaScriptConfirmPanelWithMessage!!!!") //- this doesn't get called return true } } The createWebViewWith, runJavaScriptAlertPanelWithMessage, and runJavaScriptConfirmPanelWithMessage callbacks are not being called. Can you help me with this? Thank you.
Posted Last updated
.
Post not yet marked as solved
2 Replies
397 Views
I am using Xcode 14.3.1 to develop and I have this unit test: @testable import bimb_authenticate_ios import XCTest import RxSwift import RxBlocking final class BindingApiClientTests: XCTestCase { private var disposeBag = DisposeBag() override func setUpWithError() throws { // Put setup code here. This method is called before the invocation of each test method in the class. disposeBag = DisposeBag() } override func tearDownWithError() throws { // Put teardown code here. This method is called after the invocation of each test method in the class. } func testPostInternetBankingCredentials_WhenSuccess() throws { XCTAssertEqual(1, 1) // let expectedParams = getExpectedIBCredsParams() // let expectedResponseModel = getExpectedIBCredentialsResponseModel() // let expectedData = try expectedResponseModel.jsonData() // Encodable to Data from JSON string // let expectedOutput = Single.just(expectedData) // let apiDataSource = MockDataSource(postOutputEvent: expectedOutput) // let sut = BindingApiClient(apiDataSource: apiDataSource) // // let expectation = expectation(description: "Expect Success!") // var actualResponseModel: IBCredentialsResponseModel? = try sut // .postInternetBankingCredentials(with: expectedParams) // .debug() // .toBlocking() // .first() // //// sut.postInternetBankingCredentials(with: expectedParams) //// .subscribe(onSuccess: { //// actualResponseModel = $0 //// expectation.fulfill() //// }) //// .disposed(by: disposeBag) //// //// wait(for: [expectation], timeout: 0.1) // XCTAssertEqual(expectedResponseModel, // actualResponseModel) // XCTAssertEqual(expectedParams.toJSONString(), // apiDataSource.postParamsInput?.toJSONString()) // XCTAssertTrue(apiDataSource.isPostCalled) } }` But it never run even though it only had one simple line, XCTAssertEqual(1, 1). It just started and will be processing ad infinitum. There is no log whatsoever except for the logs for successful compilations of pods and some swiftlint warnings. Can anybody help me? Thanks.
Posted Last updated
.