Get user visits count of window in appcelerator titanium - ios

I am working on ios app,,User will login to the app.I have multiple screens in one screen i have a requirement is if user first time visits that screen i need to show the instructions screen.If screen visits count more than once no need to show the instructions.
I need to store that screens count for each user separately how can we achieve this in appcelerator titanium
Please help me thanks in advance.

You could use the open or focus event to pick up when someone hits the screen and then either:
If this is a connected app, and you're downloading the user profile on login, you could store a flag to say tutorialSeen or similar. Check this when the window opens / focuses or
if not connected or you want to store locally, store the flag in the Ti.App.Properties under a user profile.
(you could equally store a count value that increments when they hit the screen but since you just want the first time captured, I'd go with a) capture event, b) check property, c) if false, set to true and show tutorial, d) if true, skip.)
Hope that helps!

I think you do not need to store the user visit count if your only purpose is to show the Instruction window only when user login into the app for first time.
You can do it this way:
someController.js
function onLoginSuccess() {
// getInt() will return the value of INSTRUCTION_WINDOW property, you can name this property whatever you want.
// if this property does not exist, then it will return the value of the second parameter.
var showInstruction = Ti.App.Properties.getInt("INSTRUCTION_WINDOW", 1);
if (showInstruction) {
Alloy.createController('instructionWindow').getView().open();
} else {
Alloy.createController('nextWindow').getView().open();
}
}
// logout function can be anywhere
// remember to set the property to 1 if you want to show the instructions again after logout and then login.
function logout() {
Ti.App.Properties.setInt("INSTRUCTION_WINDOW", 1);
}
instructionWindow.js
$.instructionWindow.addEventListener('open', function () {
// after opening the instruction window, set this property to 0
// so it won't be shown up the next time the already logged-in user opens the app
Ti.App.Properties.setInt("INSTRUCTION_WINDOW", 0);
});

first you set the nsuserdefaults value #"1".
[[NSUserDefaults standardUserDefaults] setObject:#"1" forKey:#"showtheinstruction"];
[[NSUserDefaults standardUserDefaults] synchronize];
after this you have to compare this string and shows the instruction message.
NSString *str_savedValue = [[NSUserDefaults standardUserDefaults]
stringForKey:#"showtheinstruction"];
if (str_savedValue isEqualToString:#"1") {
// show the instruction window.
}
else
{
// don't show the instruction window.
}

Related

Swift: Hide a View Controller after first time use

In swift I am making a app where it asks for a code before going to the actual app. I only want this to be showed once. How do I have this page only showed the first time then they enter the code and they only have to do this once then when they use the app again they don't need to enter a code. Thanks.
Your best shot is NSUserDefaults. Save a flag (a boolean) in NSUserDefaults to indicate whether it is the first time the user has opened the app.
let userDefaults = NSUserDefaults.standardUserDefaults()
if userDefaults.valueForKey("IS_FIRST_TIME") as? Bool != nil {
// First time, do something...
// ...
// ...
// Now, save a flag to indicate that this was the first time.
userDefaults.setValue(true, forKey: "IS_FIRST_TIME")
userDefaults.synchronize() // Needed to save the new value.
}

Autofill Username and Password in UIWebView

I'm doing a very easy app for me. When I launch this app, it simply bring me to this web page https://social.tre.it/expert.
I would like to automatise login so is there a way to autofill username and password, check the "I accept condition" mark and push "login" button?
I tried this Autofill Username and Password UIWebView Swift but it doesn't work, I'm not the creator of the page so I don't know exactly how it's structured.
Would be cool even if iCloud keychains would fill the forms...but maybe I'm asking too much!
You can use JavaScript to do it.
If you inspect the page, you can pretty easily spot the IDs of the text input fields (expert_email and expert_password) and execute some JS code to fill them.
Implement the webViewDidFinishLoad method of the UIWebView delegate like so:
OBJECTIVE-C:
- (void)webViewDidFinishLoad:(UIWebView *)webView {
//fill data
NSString *email = #"myemail#email.com";
NSString *password = #"mypassword";
NSString *fillDataJsCall = [NSString stringWithFormat:#"document.getElementById('expert_email').value = '%#';document.getElementById('expert_password').value = '%#';", email, password];
[webView stringByEvaluatingJavaScriptFromString:fillDataJsCall];
//check checkboxes
[webView stringByEvaluatingJavaScriptFromString:#"document.getElementById('expert_remember_me').checked = true; document.getElementById('expert_terms_of_service').checked = true;"];
//submit form
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^(void)
{
[webView stringByEvaluatingJavaScriptFromString:#"document.forms[\"new_expert\"].submit();"];
});
}
SWIFT:
func webViewDidFinishLoad(webView: UIWebView) {
// fill data
let savedUsername = "USERNAME"
let savedPassword = "PASSWORD"
let fillForm = String(format: "document.getElementById('expert_email').value = '\(savedUsername)';document.getElementById('expert_password').value = '\(savedPassword)';")
webView.stringByEvaluatingJavaScriptFromString(fillForm)
//check checkboxes
webView.stringByEvaluatingJavaScriptFromString("document.getElementById('expert_remember_me').checked = true; document.getElementById('expert_terms_of_service').checked = true;")
//submit form
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(1 * NSEC_PER_SEC)), dispatch_get_main_queue()){
webView.stringByEvaluatingJavaScriptFromString("document.forms[\"new_expert\"].submit();")
}
}
This should fill your info. However, this code can easily break if this website changes its structure in the future. This method of executing JS code is more reasonable when you're handling your own pages.
Edit:
I updated the code to demonstrate how to check the checkboxes and how to submit the form.
Some notes:
when the login fails the page is reloaded, so you're going to end up with an endless loop of calls to webViewDidFinishLoad since you're trying to submit over and over again, so you might want to add some logic to break in this case. That's why I put a delay before submitting in order to be able to see what's going on.
In addition to the info in the previous point - you're going to get calls to webViewDidFinishLoad anyway after login is successful (when redirected to the next page) so you might want to raise a flag once a different page loads (perform the login attempt only when on the login page).

iOS inapp purchase plugin return null

I'm using cordova to make an app in iOS store an I also use https://github.com/j3k0/cordova-plugin-purchase/blob/master/doc/api.md for integrate in-app purchase.
I already create product on my iTunes connect and put the code like
function initStore(){
if (!window.store) {
log('Store not available');
return;
}
// Enable maximum logging level
store.verbosity = store.DEBUG;
// Enable remote receipt validation
//store.validator = "https://api.fovea.cc:1982/check-purchase";
// Inform the store of your products
alert('registerProducts');
store.register({
id: 'com.thegiffary.product.quran_full',
alias: 'full version',
type: store.NON_CONSUMABLE
});
// When any product gets updated, refresh the HTML.
store.when("product").updated(function (p) {
alert(JSON.stringify(p))
});
// When purchase of the full version is approved,
// show some logs and finish the transaction.
store.when("full version").approved(function (order) {
alert('You just unlocked the FULL VERSION!');
order.finish();
});
// The play button can only be accessed when the user
// owns the full version.
store.when("full version").updated(function (product) {
alert(JSON.stringify(product))
});
// When the store is ready (i.e. all products are loaded and in their "final"
// state), we hide the "loading" indicator.
//
// Note that the "ready" function will be called immediately if the store
// is already ready.
store.ready(function() {
alert('ready')
});
// When store is ready, activate the "refresh" button;
store.ready(function() {
alert('refresh-button')
});
// Alternatively, it's technically feasible to have a button that
// is always visible, but shows an alert if the full version isn't
// owned.
// ... but your app may be rejected by Apple if you do it this way.
//
// Here is the pseudo code for illustration purpose.
// myButton.onclick = function() {
// store.ready(function() {
// if (store.get("full version").owned) {
// // access the awesome feature
// }
// else {
// // display an alert
// }
// });
// };
// Refresh the store.
//
// This will contact the server to check all registered products
// validity and ownership status.
//
// It's fine to do this only at application startup, as it could be
// pretty expensive.
alert('refresh');
store.refresh();
}
When I test the code on real device, it return product with null information (please see the picture)
I'm not sure am I miss any thing when I config the in-app product? Please give me any suggestion.
Regards.
I was facing a similar problem developing an android in-app-purchasing app. I am going to take a stab in the dark and guess that the problem might be similar. My issue was that the id for my product did not match what I was trying to pull from the store.
The product id and type have to match products defined in your Apple and Google developer consoles.
In my case, when the product loaded, it had the same field values as the one you are getting now. I changed the id, and it loaded perfectly. You may want to check those two values in your store.register function.

How to wait until Current Location dialog is answered to run a method?

What is the best practice for pushing a view controller based on the feedback from the requesting Current Location iOS-based dialog (shown in the image below)?
I am trying to determine after the selections is made to either success -> send the user onward in the flow OR fail -> show a screen that requires they allow current location.
I've gotten as far as calling this method from a method where a button-press allocates CLLocationManager:
- (void) confirmInfo {
BOOL locationAllowed = [CLLocationManager locationServicesEnabled];
if (locationAllowed==NO) {
// Show the how-to viewcontroller
} else {
// Go to the next step onboarding
}
}
But I do not know how to wait until the input comes back from the dialog to choose which VC to show the user.
You can have Delegate method user will allow or even if user dont allow.. and from that response you can continue you push pop.
Else even is you can try block based structure to maintain your flow.
following link may help you..
https://github.com/intuit/LocationManager
or
https://github.com/FuerteInternational/FTLocationManager
INTULocationManager *locMgr = [INTULocationManager sharedInstance];
[locMgr requestLocationWithDesiredAccuracy:INTULocationAccuracyCity
timeout:10.0
delayUntilAuthorized:YES // This parameter is optional, defaults to NO if omitted
block:^(CLLocation *currentLocation, INTULocationAccuracy achievedAccuracy, INTULocationStatus status) {
if (status == INTULocationStatusSuccess) {
// Request succeeded, meaning achievedAccuracy is at least the requested accuracy, and
// currentLocation contains the device's current location.
}
else if (status == INTULocationStatusTimedOut) {
// Wasn't able to locate the user with the requested accuracy within the timeout interval.
// However, currentLocation contains the best location available (if any) as of right now,
// and achievedAccuracy has info on the accuracy/recency of the location in currentLocation.
}
else {
// An error occurred, more info is available by looking at the specific status returned.
}
}];
First, create a CLLocationManager, then set your controller to its delegate, finally call [self.locationManager startUpdatingLocations]; to display the dialog.
Then use the CLLocationManagerDelegate methods to determine what the user chose:
On success,
– locationManager:didUpdateLocations:
gets called. Otherwise
– locationManager:didFailWithError:

reset a single gamecenter achievement

In my app I have an achievement for 10 wins in a row. So when the user wins 5 games in a row I report the achievement 50% completed - this works fine. When the user loses some games I call my resetAchievment method which sets the percentage to 0 and reports the percentage again. However when I restart the app the percentage gets read from the GKAchivement and it still shows 50%.
- ( void ) resetAchievement
{
_gamekitAchievement.percentComplete=0.0f;
_counter = 0;
[self report];
}
- ( void ) report
{
_gamekitAchievement.showsCompletionBanner = YES;
[_gamekitAchievement reportAchievementWithCompletionHandler:^(NSError *error)
{
if (error)
{
NSLog(#"reporting Achievment: %# failed, error: %#", _gamekitAchievement.identifier, [error localizedDescription]);
}
}];
}
Is it not possible to report a smaller percentage again - or am I doing something wrong?
I have no actual experience from GameKit at all but from reading the documentation and searching the web it seems you're only able to report progress and not regression(?) Not to mention the fact that you can only reset ALL achievements... Perhaps the following would still help you achieve (ahem) what you want:
Update all your local achievement data with + (void)loadAchievementsWithCompletionHandler:
Store this data in the userDefaults for safety
Do NOT reset the local achievement data
Reset all the achievements with + (void)resetAchievementsWithCompletionHandler:
Change the percentComplete to 0 on the achievement in question.
report progress of all the achievements from your local storage
Now, as I mention, having no hands-on experience with this framework the above might not be practical for a number of reasons I am unaware of (the way progress is presented to the player for instance). Guess it was worth a shot to share the idea anyways...
Short answer: It is not possible to report a smaller percentage again.
Long answer: A lower GameCenter score will not overwrite a higher one.
For example you have a high score of 10 points and it's recorded in GameCenter.
If in the next try you get 5 points and they are submitted to GC, your high score of 10 won't be affected.
Similarly if you try to 'reset' your score, it counts as submitting a new score of 0, so it won't make a difference.
This only applies to scores and achievements submitted to GameCenter, inside your app you can do anything you want (for example your own custom leaderboard or something)
If you think about it, 5 wins is not 50% of the way there, since they could lose the 6th, then win 10 in a row, in which case they played 16 total games and 5 wins was more like 30% of the way there. In this case, it is all or nothing, so don't report anything until they have all 10.
Please be aware that storing the progress towards an achievement in NSUserDefaults doesn't take different GameCenter users into account. That means, if Player A (logged into GameCenter) makes some progress and at 90 % progress another Player B on the same device logs into GameCenter with his own account, he starts with the progress made by Player A.
You might solve this by storing a whole NSDictionary with the Player IDs as keys into NSUserDefaults.
What you'll want to do is save it NSUserdefaults. then, Call the NSUser default and check what number it is by using an IF statement.
-(void)checkAcheivement{
scoreNumber = [NSUserDefaults standardUserDefaults] objectForKey:#"GamesWon"]
if(scoreNumber == 10){
//Run code to save achievement in Game Center(_gamekit stuff)
}
//-(void)checkScoreFire{
//scoreNumber = [NSUserDefaults standardUserDefaults] objectForKey:#"GamesWon"]
//if(scoreNumber == 5){
//Run code to set up alert view for 5 wins below
//UIAlertView* message = [[UIAlertView alloc]
// initWithTitle: #"Alert"
// message: #"You are halfway to the Achievement!"
// delegate: self
// cancelButtonTitle: #"Dismiss"
// [message show];
//}
//to save score use this method:
-(void)saveScore{
scoreNumber = [NSUserDefaults standardUserDefaults] objectForKey:#"GamesWon"]
if(gameScore > scoreNumber){
[[NSUserDefaults standardUserDefaults]setInteger:scoreNumber forKey:#"GamesWon"];
}
This will only post the achievement if it is ten, i suggest not putting the achievement in until then, because it makes it more difficult. I also suggest setting up an AlertView to let the person know they are halfway there. You can do so with the code commented above with the checkScoreFive method. Remember to declare everything in the .h file as well.
IBOutlet UIAlertView *AlertView;
-(void)checkAcheivement;
-(void)checkScoreFire;
-(void)saveScore;
int gameScore;
int scoreNumber;

Resources