#StackBounty: #ios #swift #cookies #uiwebview iOS How to add cookie to each UIWebView request?

Bounty: 100

I need to open URL with Angular in UIWebView and I need to send cookie with each UIWebView request.

What I tried to do:

I tried to check if request contains cookie. If it does UIWebView performs request, if not I create the same request but with cookie and perform it. To substitute requests I used UIWebViewDelegate‘s method func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebViewNavigationType) -> Bool. But it works not as I expected, some requests performs without cookies.

My code:

final class FieldServiceViewController: UIViewController {

    private var webView = UIWebView()
    private var sessionID = String()

    override func viewDidLoad() {
        super.viewDidLoad()

        _ = JSONAPI.getSessionID().subscribe(onNext: { [weak self] sessionID in
            self?.sessionID = sessionID
            self?.configureUI()
            let string = "https://someURL"
            let url = URL(string: string)
            let request = URLRequest(url: url!)
            self?.webView.loadRequest(request)
        })
    }

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        webView.frame = view.bounds
    }

    private func configureUI() {
        webView.delegate = self
        view.addSubview(webView)
    }

    private func cookedRequest(from: URLRequest) -> URLRequest? {

        let cookiesKey = "Cookie"
        let headers = from.allHTTPHeaderFields ?? [:]
        if (headers.contains { $0.0 == cookiesKey }) {
            return nil
        }

        var request = from
        request.cachePolicy = .reloadIgnoringLocalAndRemoteCacheData
        let cookiesToAdd = "SESSIONID=(sessionID)"
        request.addValue(cookiesToAdd, forHTTPHeaderField: cookiesKey)
        return request
        }
    }

    extension FieldServiceViewController: UIWebViewDelegate {

    func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebViewNavigationType) -> Bool {

        if let cooked = cookedRequest(from: request) {
            webView.loadRequest(cooked)
            return false
        }

        return true
    }
}

How to add cookie to each UIWebView request?

P.S. I also saved cookie in HTTPCookieStorage, but looks like there is no connection between UIWebView‘s requests and shared storage at all.


Get this bounty!!!

#StackBounty: #ios #swift #uitextview Change UITextView text by using its tag number to identify the element due for change

Bounty: 50

//UITextView Creation
let textarea  = UITextView (frame : CGRect (x: 40, y: 100 ,width:100 , height:100))
                                            textarea.delegate = self
                                            textarea.tag = self.numarr
                                            textarea.backgroundColor = UIColor(red: 0.9686, green: 0.9686, blue: 0.9686, alpha: 1.0)
                                            textarea.layer.cornerRadius = 20.0
                                            textarea.contentInset = UIEdgeInsetsMake(5, 5, 5, 5);
                                            textarea.layer.masksToBounds = true
                                            self.scrollviewxp.addSubview(textarea)   

//Later after, the button function
 @IBAction func loadbutton(_ sender: Any) {

if let hellatextview = self.scrollviewxp.viewWithTag(index) as? UITextView
                        {

                            hellatextview.text = "success"
                        }

                                         }

The above code is not flagged as an error on Xcode but doesn’t change the UITextView (hellatextview) value upon execution. A textView with the tag number (index) exists but isn’t being changed.

Any ideas why it isn’t working? Ive had the same issue with UIButtons


Get this bounty!!!

#StackBounty: #c# #ios #xamarin #xamarin.forms Customizing a Progress Bar appearance in Xamarin.Forms

Bounty: 50

I used Drawable to customize the rendering of the ProgressBar in Android as answered to this question but the solution is not working with iOS.

Below is how it renders in Android.
enter image description here

Below is how it renders in iOS
enter image description here

Below is the code for my iOS CustomRenderer

[assembly: ExportRenderer(typeof(CustomProgressbar), typeof(CustomProgressBarRenderer))]
namespace Demo.iOS.Renderers
{
public class CustomProgressBarRenderer : ProgressBarRenderer
{
    protected override void OnElementChanged(ElementChangedEventArgs<ProgressBar> e)
    {
        try
        {
            base.OnElementChanged(e);

            if (Control != null)
            {                
               Control.ProgressTintColor = Color.FromHex("#ff0000").ToUIColor();                       
               Control.TrackTintColor = Color.FromHex("#3489cc").ToUIColor();
             } 
        }
        catch (Exception ex)
        {

        }
    }

    public override void LayoutSubviews()
    {
        base.LayoutSubviews();
        var X = 1.0f;
        var Y = 15.0f;
        CGAffineTransform _transform = CGAffineTransform.MakeScale(X, Y);
        this.Transform = _transform;
        this.ClipsToBounds = true;
        this.Layer.MasksToBounds = true;
        this.Layer.CornerRadius = 5;
    }
}

}

How do I accomplish this?


Get this bounty!!!

#StackBounty: #ios #realm #realm-migration CoreData to Realm migration and Realm internal migrations as separate steps

Bounty: 100

I have a production app where data is stored using CoreData framework, and I cannot make a clean break as the data contains only user-generated content and it is not synced to anywhere. I would not like to support CoreData migration to the latest version of the Realm database I have, I would like to migrate CoreData file into the very first version of my realm database, then apply realm migrations. Is this possible?

I thought Realm.Configuration(objectTypes: [MyClass.self, MyOtherClass.self]) will help me, but this only covers the case when new classes added when I have same classes with a different set of properties.


Get this bounty!!!

#StackBounty: #ios #xcode-ui-testing #xcuitest Stop scrolling on UITableView at last during XCUI TestCase

Bounty: 50

In my one of UITableView have more then 10 rows. I want to scroll till last row while UITestCase running.

I have written below code to scroll till last row.

-(void)scrollToElement:(XCUIElement *)element application:(XCUIApplication *)app{
    while ([self visible:element withApplication:app]) {
        XCUIElement *searchResultTableView = app.tables[@"searchResultView"];
        XCUICoordinate *startCoord = [searchResultTableView coordinateWithNormalizedOffset:CGVectorMake(0.5, 0.5)];
        XCUICoordinate *endCoord = [startCoord coordinateWithOffset:CGVectorMake(0.0, -262)];
        [startCoord pressForDuration:0.01 thenDragToCoordinate:endCoord];
    }
}
-(BOOL)visible:(XCUIElement *)element withApplication:(XCUIApplication *)app{
    if (element.exists && !CGRectIsEmpty(element.frame) && element.isHittable) {
        return CGRectContainsRect([app.windows elementBoundByIndex:0].frame, element.frame);
    } else {
        return FALSE;
    }
}

An i have called above method in my one of UITestCase method by below code

XCUIElement *searchResultTableView = app.tables[@"searchResultView"];
[self waitForElementToAppear:searchResultTableView withTimeout:30];


XCUIElement *table = [app.tables elementBoundByIndex:0];
XCUIElement *lastCell = [table.cells elementBoundByIndex:table.cells.count - 1];
[self scrollToElement:lastCell application:app];

By this code i can scroll to last row but after reaching last row, it continue doing scroll means can’t stop scrolling.

Please help me to scroll to only last row and then it should stop to scroll so that i can perform next action event.

I have refer StackOverFlow answer but none of them meet my requirement.

Thanks in advance.


Get this bounty!!!

#StackBounty: #ios #exc-bad-access #avaudiosession Crash in AVAudioSession currentRoute

Bounty: 50

We have received a number of crash reports from the app. They all look similar. The call [AVAudioSession currentRoute] is on the top of each crashed stack:

Exception Type:  EXC_BAD_ACCESS (SIGSEGV)  
Exception Subtype: KERN_INVALID_ADDRESS at 0x0000000c0b25beb8  
Termination Signal: Segmentation fault: 11  
Termination Reason: Namespace SIGNAL, Code 0xb  
Terminating Process: exc handler [0]  
Triggered by Thread:  14  
...  

Thread 14 name:  
Thread 14 Crashed:  
0  libobjc.A.dylib  objc_msgSend + 16  
1  AVFAudio          -[AVAudioSession currentRoute] + 140 (AVAudioSession.mm:1715)  
...  

We found that the crash happens in the handler of AVAudioSessionRouteChangeNotification notification. In this handler we are posting an asyncronous call on our custom serial queue, where we are getting the current route and enumerating through all the outputs.

- (instancetype)init  
{  
    if (self = [super init])  
    {  
          _commandsQueue = dispatch_queue_create("com.app.commandsQueue", DISPATCH_QUEUE_SERIAL);  
          [[NSNotificationCenter defaultCenter] addObserver:self  
              selector:@selector(handleRouteChanged:)  
              name:AVAudioSessionRouteChangeNotification  
              object:nil];  
    }  
    return self;  
}  

- (void)handleRouteChanged:(NSNotification *)notification  
{  
    dispatch_async(self.commandsQueue, ^{  
        AVAudioSession *audioSession = [AVAudioSession sharedInstance];  
        AVAudioSessionRouteDescription* currentRoute = audioSession.currentRoute;  
        for (AVAudioSessionPortDescription *outputPort in currentRoute.outputs)  
        {  
            if ([outputPort.portType isEqualToString:AVAudioSessionPortAirPlay])  
            {  
                // updating dictionary with status  
            }  
        }  
    });  
}  

We are not able to reproduce the issue and we do not know the exact scenario. We played a lot with different route change scenarios, but we observed no crashes.
Does anyone have an idea about any possible root cause of this crash?


Get this bounty!!!

#StackBounty: #object-oriented #design-patterns #swift #ios Swift/iOS component for label with clickable text buttons

Bounty: 100

So I’m creating a component based on UILabel, which I’m calling RichLabel. The main goal is to add support for clickable links (multiple). It should also be possible to to differentiate between types of links, so I can handle them differently. For instance one link should open ModalWindowA and another ModalWindowB.

I have something that works, but it’s not a very solid solution, and would love some input on the design.

RichButton

RichButton is the different types of button/links I currently support in the RichText.

protocol RichButton {
  var id: String { get }
  var buttonTitle: String { get }
}

struct ProfileRichButton: RichButton {

  let id: String
  let buttonTitle: String

  init(id: String = UUID().uuidString, buttonTitle: String) {
    self.id = id
    self.buttonTitle = buttonTitle
  }

}

struct AttendeesRichButton: RichButton {

  let id: String
  let buttonTitle: String

  init(id: String = UUID().uuidString, buttonTitle: String) {
    self.id = id
    self.buttonTitle = buttonTitle
  }

}

struct MeetingRichButton: RichButton {

  let id: String
  let buttonTitle: String

  init(id: String = UUID().uuidString, buttonTitle: String) {
    self.id = id
    self.buttonTitle = buttonTitle
  }

}

RichLabelComponent

RichLabelComponent is holding the data for the RichLabelComponentView and formats the text and highlights the clickable text.

protocol Component {
  var id: String { get }
}

struct RichLabelComponent: Component {

  let id: String
  let text: String
  let buttons: [RichButton]

  var formattedText: String {
    let buttonTitles = buttons.map { $0.buttonTitle }
    let formattedString = String(format: text, arguments: buttonTitles)
    return formattedString
  }

  var attributedText: NSAttributedString? {
    let attributedText = NSMutableAttributedString(string: formattedText)
    let nsFormattedText = NSString(string: formattedText)
    attributedText.setAttributes([.font: Theme.regular(size: .large)], range: formattedText.whole)
    for button in buttons {
      let range = nsFormattedText.range(of: button.buttonTitle)
      let attributedButtonTitle = NSAttributedString(string: button.buttonTitle, attributes: [.foregroundColor: Theme.secondaryOrangeColor, .font: Theme.regular(size: .large)])
      attributedText.replaceCharacters(in: range, with: attributedButtonTitle)
    }
    return attributedText
  }

  init(id: String = UUID().uuidString, text: String) {
    self.id = id
    self.text = text
    self.buttons = []
  }

  init(id: String = UUID().uuidString, text: String, buttons: RichButton...) {
    self.id = id
    self.text = text
    self.buttons = buttons
  }
}

RichLabelComponentView

This is the view responsible for displaying the formatted label, and handles the tapGesture.

protocol RichLabelComponentViewDelegate: class {
  func richLabelComponentView(_ richLabelComponentView:   RichLabelComponentView, didTapButton button: RichButton, forComponent  component: RichLabelComponent)
}

class RichLabelComponentView: UIView {

  // MARK: - Internal properties

  private lazy var label: UILabel = {
    let label = UILabel()
    label.numberOfLines = 0
    label.lineBreakMode = .byWordWrapping
    label.textAlignment = .left
    label.isUserInteractionEnabled = true
    label.translatesAutoresizingMaskIntoConstraints = false
    return label
  }()

  private lazy var tapGestureRecognizer: UITapGestureRecognizer = {
    let tapGestureRecognizer = UITapGestureRecognizer()
    tapGestureRecognizer.addTarget(self, action: #selector(tapHandler(gesture:)))
    return tapGestureRecognizer
  }()

  // MARK: - External properties

  weak var delegate: RichLabelComponentViewDelegate?

  var component: RichLabelComponent? {
    didSet {
      label.attributedText = component?.attributedText
    }
  }

  // MARK: - Setup

  override init(frame: CGRect) {
    super.init(frame: frame)
    self.addGestureRecognizer(tapGestureRecognizer)
    self.addSubviewsAndConstraints()
  }

  required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }

  private func addSubviewsAndConstraints() {
    addSubview(label)

    label.leftAnchor.constraint(equalTo: self.leftAnchor).isActive = true
    label.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true
    label.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
    label.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
  }

  // MARK: - Actions

  @objc func tapHandler(gesture: UITapGestureRecognizer) {
    guard let component = component, let delegate = delegate else {
      return
    }

    for button in component.buttons {
      let nsString = component.formattedText as NSString
      let range = nsString.range(of: button.buttonTitle)
      if tapGestureRecognizer.didTapAttributedText(label: label, inRange: range) {
        delegate.richLabelComponentView(self, didTapButton: button, forComponent: component)
      }
    }
  }
}

This is the implementation which recognises if one of the text links/buttons where tapped:

extension UIGestureRecognizer {

  /**
   Returns `true` if the tap gesture was within the specified range of the attributed text of the label.

   - Parameter label:   The label to match tap gestures in.
   - Parameter targetRange: The range for the substring we want to match tap against.

   - Returns: A boolean value indication wether substring where tapped or not.
   */
  func didTapAttributedText(label: UILabel, inRange targetRange: NSRange) -> Bool {
    guard let attributedString = label.attributedText else { fatalError("Not able to fetch attributed string.") }

    var offsetXDivisor: CGFloat
    switch label.textAlignment {
    case .center: offsetXDivisor = 0.5
    case .right: offsetXDivisor = 1.0
    default: offsetXDivisor = 0.0
    }

    let layoutManager = NSLayoutManager()
    let textContainer = NSTextContainer(size: .zero)
    let textStorage = NSTextStorage(attributedString: attributedString)
    let labelSize = label.bounds.size

    layoutManager.addTextContainer(textContainer)
    textStorage.addLayoutManager(layoutManager)

    textContainer.lineFragmentPadding = 0.0
    textContainer.lineBreakMode = label.lineBreakMode
    textContainer.maximumNumberOfLines = label.numberOfLines
    textContainer.size = labelSize

    let locationOfTouchInLabel = self.location(in: label)
    let textBoundingBox = layoutManager.usedRect(for: textContainer)

    let offsetX = (labelSize.width - textBoundingBox.size.width) * offsetXDivisor - textBoundingBox.origin.x
    let offsetY = (labelSize.height - textBoundingBox.size.height) * 0.5 - textBoundingBox.origin.y
    let textContainerOffset = CGPoint(x: offsetX, y: offsetY)

    let locationTouchX = locationOfTouchInLabel.x - textContainerOffset.x
    let locationTouchY = locationOfTouchInLabel.y - textContainerOffset.y
    let locationOfTouch = CGPoint(x: locationTouchX, y: locationTouchY)

    let indexOfCharacter = layoutManager.characterIndex(for: locationOfTouch, in: textContainer, fractionOfDistanceBetweenInsertionPoints: nil)

    return NSLocationInRange(indexOfCharacter, targetRange)
  }
}

How to use the component

let component = RichLabelComponent(text: "Hello %@. You are meeting with %@.", buttons: ProfileRichButton(buttonTitle: "Your Name"), AttendeesRichButton(buttonTitle: "Eve and Bob"))
let view = RichLabelComponentView()
view.component = component
view.delegate = self

I can then send button, and on the delegate method I can then switch on button.self and check for case is ProfileRichButton for instance, so I can know which type of link was clicked.

The problems

What I don’t like about this solution is for instance the need to use NSString.range(of: "") to set properties. If suddenly there are two links with same name, this won’t work.

Any ideas how to improve this or restructure it in a more flexible and solid way?


Get this bounty!!!

#StackBounty: #object-oriented #swift #ios Swift/iOS component for label with clickable text buttons

Bounty: 100

So I’m creating a component based on UILabel, which I’m calling RichLabel. The main goal is to add support for clickable links (multiple). It should also be possible to to differentiate between types of links, so I can handle them differently. For instance one link should open ModalWindowA and another ModalWindowB.

I have something that works, but it’s not a very solid solution, and would love some input on the design.

RichButton

RichButton is the different types of button/links I currently support in the RichText.

protocol RichButton {
  var id: String { get }
  var buttonTitle: String { get }
}

struct ProfileRichButton: RichButton {

  let id: String
  let buttonTitle: String

  init(id: String = UUID().uuidString, buttonTitle: String) {
    self.id = id
    self.buttonTitle = buttonTitle
  }

}

struct AttendeesRichButton: RichButton {

  let id: String
  let buttonTitle: String

  init(id: String = UUID().uuidString, buttonTitle: String) {
    self.id = id
    self.buttonTitle = buttonTitle
  }

}

struct MeetingRichButton: RichButton {

  let id: String
  let buttonTitle: String

  init(id: String = UUID().uuidString, buttonTitle: String) {
    self.id = id
    self.buttonTitle = buttonTitle
  }

}

RichLabelComponent

RichLabelComponent is holding the data for the RichLabelComponentView and formats the text and highlights the clickable text.

protocol Component {
  var id: String { get }
}

struct RichLabelComponent: Component {

  let id: String
  let text: String
  let buttons: [RichButton]

  var formattedText: String {
    let buttonTitles = buttons.map { $0.buttonTitle }
    let formattedString = String(format: text, arguments: buttonTitles)
    return formattedString
  }

  var attributedText: NSAttributedString? {
    let attributedText = NSMutableAttributedString(string: formattedText)
    let nsFormattedText = NSString(string: formattedText)
    attributedText.setAttributes([.font: Theme.regular(size: .large)], range: formattedText.whole)
    for button in buttons {
      let range = nsFormattedText.range(of: button.buttonTitle)
      let attributedButtonTitle = NSAttributedString(string: button.buttonTitle, attributes: [.foregroundColor: Theme.secondaryOrangeColor, .font: Theme.regular(size: .large)])
      attributedText.replaceCharacters(in: range, with: attributedButtonTitle)
    }
    return attributedText
  }

  init(id: String = UUID().uuidString, text: String) {
    self.id = id
    self.text = text
    self.buttons = []
  }

  init(id: String = UUID().uuidString, text: String, buttons: RichButton...) {
    self.id = id
    self.text = text
    self.buttons = buttons
  }
}

RichLabelComponentView

This is the view responsible for displaying the formatted label, and handles the tapGesture.

protocol RichLabelComponentViewDelegate: class {
  func richLabelComponentView(_ richLabelComponentView:   RichLabelComponentView, didTapButton button: RichButton, forComponent  component: RichLabelComponent)
}

class RichLabelComponentView: UIView {

  // MARK: - Internal properties

  private lazy var label: UILabel = {
    let label = UILabel()
    label.numberOfLines = 0
    label.lineBreakMode = .byWordWrapping
    label.textAlignment = .left
    label.isUserInteractionEnabled = true
    label.translatesAutoresizingMaskIntoConstraints = false
    return label
  }()

  private lazy var tapGestureRecognizer: UITapGestureRecognizer = {
    let tapGestureRecognizer = UITapGestureRecognizer()
    tapGestureRecognizer.addTarget(self, action: #selector(tapHandler(gesture:)))
    return tapGestureRecognizer
  }()

  // MARK: - External properties

  weak var delegate: RichLabelComponentViewDelegate?

  var component: RichLabelComponent? {
    didSet {
      label.attributedText = component?.attributedText
    }
  }

  // MARK: - Setup

  override init(frame: CGRect) {
    super.init(frame: frame)
    self.addGestureRecognizer(tapGestureRecognizer)
    self.addSubviewsAndConstraints()
  }

  required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }

  private func addSubviewsAndConstraints() {
    addSubview(label)

    label.leftAnchor.constraint(equalTo: self.leftAnchor).isActive = true
    label.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true
    label.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
    label.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
  }

  // MARK: - Actions

  @objc func tapHandler(gesture: UITapGestureRecognizer) {
    guard let component = component, let delegate = delegate else {
      return
    }

    for button in component.buttons {
      let nsString = component.formattedText as NSString
      let range = nsString.range(of: button.buttonTitle)
      if tapGestureRecognizer.didTapAttributedText(label: label, inRange: range) {
        delegate.richLabelComponentView(self, didTapButton: button, forComponent: component)
      }
    }
  }
}

This is the implementation which recognises if one of the text links/buttons where tapped:

extension UIGestureRecognizer {

  /**
   Returns `true` if the tap gesture was within the specified range of the attributed text of the label.

   - Parameter label:   The label to match tap gestures in.
   - Parameter targetRange: The range for the substring we want to match tap against.

   - Returns: A boolean value indication wether substring where tapped or not.
   */
  func didTapAttributedText(label: UILabel, inRange targetRange: NSRange) -> Bool {
    guard let attributedString = label.attributedText else { fatalError("Not able to fetch attributed string.") }

    var offsetXDivisor: CGFloat
    switch label.textAlignment {
    case .center: offsetXDivisor = 0.5
    case .right: offsetXDivisor = 1.0
    default: offsetXDivisor = 0.0
    }

    let layoutManager = NSLayoutManager()
    let textContainer = NSTextContainer(size: .zero)
    let textStorage = NSTextStorage(attributedString: attributedString)
    let labelSize = label.bounds.size

    layoutManager.addTextContainer(textContainer)
    textStorage.addLayoutManager(layoutManager)

    textContainer.lineFragmentPadding = 0.0
    textContainer.lineBreakMode = label.lineBreakMode
    textContainer.maximumNumberOfLines = label.numberOfLines
    textContainer.size = labelSize

    let locationOfTouchInLabel = self.location(in: label)
    let textBoundingBox = layoutManager.usedRect(for: textContainer)

    let offsetX = (labelSize.width - textBoundingBox.size.width) * offsetXDivisor - textBoundingBox.origin.x
    let offsetY = (labelSize.height - textBoundingBox.size.height) * 0.5 - textBoundingBox.origin.y
    let textContainerOffset = CGPoint(x: offsetX, y: offsetY)

    let locationTouchX = locationOfTouchInLabel.x - textContainerOffset.x
    let locationTouchY = locationOfTouchInLabel.y - textContainerOffset.y
    let locationOfTouch = CGPoint(x: locationTouchX, y: locationTouchY)

    let indexOfCharacter = layoutManager.characterIndex(for: locationOfTouch, in: textContainer, fractionOfDistanceBetweenInsertionPoints: nil)

    return NSLocationInRange(indexOfCharacter, targetRange)
  }
}

How to use the component

let component = RichLabelComponent(text: "Hello %@. You are meeting with %@.", buttons: ProfileRichButton(buttonTitle: "Your Name"), AttendeesRichButton(buttonTitle: "Eve and Bob"))
let view = RichLabelComponentView()
view.component = component
view.delegate = self

I can then send button, and on the delegate method I can then switch on button.self and check for case is ProfileRichButton for instance, so I can know which type of link was clicked.

The problems

What I don’t like about this solution is for instance the need to use NSString.range(of: "") to set properties. If suddenly there are two links with same name, this won’t work.

Any ideas how to improve this or restructure it in a more flexible and solid way?


Get this bounty!!!

#StackBounty: #jquery #ios #mobile-safari How to programatically focus on a textfield on page load for mobile safari?

Bounty: 200

Background

I am developing a standalone web app for iPod Touch. One of my requirements is to focus on a textfield when a page loads so that a user can do a task continually (e.g. with a barcode reader).

Problem

The problem is that it does focus on the text field in question, but the keyboard does not go up. Is there a workaround for this? Or is this by design by Apple?

Sample Html

I’m unsure on how to put this into a code snippet, but this is where I’ve been experimenting on:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0.0">

    <meta name="apple-mobile-web-app-capable" content="yes">
    <link rel="apple-touch-icon" href="https://cdn57.androidauthority.net/wp-content/uploads/2016/06/android-win-2-300x162.png">

    <title>TESTING</title>

    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">

    https://code.jquery.com/jquery-3.2.1.min.js
    https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js

    
        // javascript goes here
    
</head>
<body>

    <section id="content">

        
Testing textfield focus
</div> </form> </div> </section> </body> </html>

I view this on Safari, then add it to the homescreen so that it would act as a standalone web app.

Attempts

I tried searching around for solutions, the first one(I lost the link) suggested to try timeouts like so:

$(function () {
    var firstResponder = $(".first-responder");
    setTimeout(function() {
        firstResponder.focus();

    }, 1000);

})

Another of the solutions I found suggested to set the selection range like so:

$(function () {
    var firstResponder = $(".first-responder");
    setTimeout(function() {
        firstResponder[0].setSelectionRange(0, 9999);

    }, 1000);

})

There was also a suggestion to bind it to a click like so:

$(function () {
    var firstResponder = $(".first-responder");
    firstResponder.on('click', function() {
        firstResponder.focus();
    });

    firstResponder.focus().click();
})

I also tried triggering a touchstart like so:

$(function () {
    var firstResponder = $(".first-responder");
    firstResponder.on('touchstart', function() {
        firstResponder.focus();
    });

    firstResponder.trigger('touchstart');
})

I also tried with a simple ajax call like so (don’t mind the success/error. All I wanted to do was focus after ajax call):

function doAjax() {
    var firstResponder = $(".first-responder");

    $.ajax({
        url: "#",
        method: "POST",
        dataType: "json",
        success: function(result) {
            firstResponder.focus();
        },
        error: function(request, error) {
            firstResponder.focus();         
        }
    });
}

I got kind of desperate so I tried setting some css too:

user-select: text;
-webkit-user-select: text;

These solutions worked on iOS 9.1 (except the css one) but all of them failed on iOS 11.1.1. I tried combining various solutions, setting timeouts, etc. but none seem to work. As I noted, it does focus because I can see that the textfield’s borders turn blue, signifying that it has focus. But I need to have the keyboard displayed too.

This behavior seems to be either a bug or a usability/security feature. If this is by design (i.e. a security feature), is there an official documentation by Apple that talks about this?

Addendum

If you think that the barcode reader might be the problem, this is not true. In the project I’m working on, the barcode reader replaces the native keyboard. In theory, even without the barcode, as long as I am able to bring up the keyboard on page load, I should be able to fulfill my requirement.

Continuous task is possible because the barcode reader can include an Enter key after the barcode it reads, thereby submitting the form the textfield is on. After the page reloads, if the textfield gets automatically focused, all the user needs to do is read another barcode. The page submits again, reloads, autofocuses, and the cycle can be repeated.


Get this bounty!!!

#StackBounty: #ios #swift #app-store #review #skstorereviewcontroller Is there a minimum time between prompts for SKStoreReviewControll…

Bounty: 100

I understand that when we call SKStoreReviewController.requestReview(), Apple decides whether to show a review prompt based on a variety of factors. What I’m curious about is the minimum time between prompts for our app. According to Apple, there is some limit (emphasis mine):

If the user hasn’t already given feedback and a request hasn’t been
made too recently
, the system displays an in-app prompt that asks for
a rating and an optional written review.

I understand that there are no guarantees about the behavior of this call beyond what’s in its documentation, but I’m wondering what happens in practice.

I’m trying to figure out whether we need to implement our own logic to wait a reasonable amount of time before requesting the prompt again, or if Apple’s definition of “recently” is good enough for this purpose.


Get this bounty!!!