I am deep linking into my app, or at least trying to. Let's make a fictional example:
// my clock app
myapp://timer?102seconds
If I understand deep links correctly, they kind of work like URLs on websites. Go to the page described in the link. This I don't need and honestly I don't think it would work even. I have a few screens on the App which I want to be able to be called like a Trigger.
In the example above I want the app to receive timer?102seconds, so that my app itself can
-be opened with the uri
is it a timer or a stopwatch or an alarm
if it is a timer, how long should it be
push the timer page on the navigator
give the bloc the info of time that I need here
I am not sure how possible that is, but it is the easiest way I can imagine implementing this here. Thanks!
If you use Firebase Dynamic Links you can encode another link, from which you can extract data. Check out this link to see documentation on how to do that.
Related
Objective: I want to develop an UI application that runs a service/ task/method
periodically to update database. This service should start after
periodically even if my application is not active/visible/user exits
app. Similar to an Android Service .
I'm using BlackBerry Java 7.1 SDK eclipse plugin .
The options I came across are the following:
1) How to run BlackBerry application in Background
This link suggests that I extend Application instead of UIApplication. But I can't do that as my application has a user interface.
2) Make application go in background
I don't want my UI application to go in background, instead i just want my application to call the service periodically .
3) Run background task from MainScreen in BlackBerry?
This link suggests to run I a thread, but I don't think that if user exits my application then the thread will run in background
4) Blackberry Install background service from UI application?
This suggests using CodeModuleManager ,whose usage I'm unable to figure .
Please suggest what is the best way to achieve this objective or suggests any other better method .
I am new to blackberry so please pardon my ignorance.
To expand on Peter's Answer:
You will need to create two classes :
class BgApp extends Applicaton
class UiApp extends UiApplication
I guess you have already created the class that extends UiApplicaiton. So add another class that extends Application.
Then create a class that extends TimerTask and implement its run method to call the method that updates the database.
class UpdateDatabaseTask extends TimerTask
In the BgApp constructor, create a Timer. And schedule the UpdateDatabaseTask using the schedule(TimerTask, long, long) method.
Define alternate entry points, check the "Do not show on homescreen" and "auto run on startup" checkboxes for the bgapp's entry point.
It is easiest and simplest to use the builtin persistence mechanism (PersistentStore and Persistable interface) for storing data. Even if you use any other means like RecordStore or SQLDb, both UiApp and BgApp can use access the same database. The values updated by the bgapp will be accessible by the uiapp and vice-versa, automatically.
If you want to send a signal from bgapp to uiapp (for example when bgapp downloads new data you want the uiapp to reload the data instantaneously), post a Global Event (ApplicationManager.postGlobalEvent()) when the download is complete and listen for it in the screen that is displaying the data (GlobalEventListener interface).
There are code samples for each of these available as part of the SDK or search on the internet and you'll find a lot of implementations.
Good research, lots of interesting thoughts.
I think the best thing to do is to try the simple standard approaches and only make something more sophisticated if you need to.
Here are two options that would be regarded as 'standard', with brief advantages and disadvantages:
a) Make your UiApplication go to the Background
Instead of exiting when the user presses the 'close' button, your UiApplication will "requestBackground()". it will automatically be bought to the foreground when the user clicks on the icon, or selects your application from the task switcher. Then you can run a Thread whenever you want or in fact leave one running to update the database.
This is my preferred method. But you have to careful with memory management to make sure there are no leaks. And some people don't like the idea that the Application is visible on the Task Switcher all the time.
b) Alternate Entry
With this option, your one Application package contains two Applications, or more accurately, one Application and one UiApplication. The UiApplication is run when the user clicks on the icon. The Application runs as a background task, and updates the database for your UiApplication.
This looks like a more elegant solution, but introduces some possible communication issues, and is more difficult to debug.
In your case, since you are relatively new to BB, I would suggest that you use option a, and if you find it doesn't work for you, you will not find it that difficult to swap to option b.
And to comment on the Options you have already presented:
Sort of covered with option b
Option a
You are correct - if an Application exits, all the Threads are killed
Leaves the problem of creating the application in the first place and then debugging it. This is not really a solution for you, more an implementation method.
The above is brief, please ask if it is not clear.
This might help with b:
http://supportforums.blackberry.com/t5/Java-Development/Set-up-an-alternate-entry-point-for-an-application/ta-p/444847
Edit:
Editing this to respond to the questions and to expand on the alternative answer, which expanded on this one (bit circular I know...).
To answer the second question first, I agree with the other answer which states the alternate entry (background) and the foreground app can share an SQLite database.
With respect to how these two communicate, while they work just fine, personally I am not a great fan of Global Events because they are propagated to all Applications on the BlackBerry. You can achieve similar things in many alternative ways - the trick is to find something that is common to both applications so that they can communicate. To this end, I recommend using RuntimeStore. See this KB article:
http://supportforums.blackberry.com/t5/Java-Development/Create-a-singleton-using-the-RuntimeStore/ta-p/442854
Regarding how you persist your database, I like PersistentStore because it is present on all devices. But if you really have a database, and not persistent Objects, then SQLite seems the ideal thing to use. Personally I would not use RecordStore, but here is a discussion of the options:
http://supportforums.blackberry.com/t5/Java-Development/Introduction-to-Persistence-Models-on-BlackBerry/ta-p/446810
And just a clarification - in the example given, you have two applications, BgApp and UiApp. You will only have one main() method. This main method will use the args that you specify to determine which one to start, which it will create and have it "enter the dispatcher". If I could make a recommendation - use "gui" as the argument to specify that you will start your UiApplication. I have experienced a circumstance that the OS attempted to start my alternate entry Ui application with this String, regardless of what I had actually specified. Might have been a one off, but I have stuck to doing that ever since.
Finally two comments on the use of Timers and Timertask to provide triggered events. The first comment to make is whatever you run in the TimerTask should not take that long - so you should just use the TimerTask to initiate the download Thread (which might take a long time). Secondly for me, in this situation, I would not use Timer/TimerTask. I would rather just have a single Thread, which 'waits', and then processes. The advantage to me is that this can be adaptive. For example, if you fail to connect, then you might shorten the time till the next connection attempt. Or if it is after hours, then you might lengthen the time between connections to reduce battery usage. Or you might stop connecting completely when the battery is very low.
Hope this helps.
Me and my team are currently rookie developers in Objective-C (less than 3 months in) working on the development of a simple tab based app with network capabilities that contains a navigator controller with a table view and a corresponding detailed view in each tab. The target is iOS 4 sdk.
On the networking side, we have a single class that functions as a Singleton that processes the NSURLConnection for each one of the views in order to retrieve the data we need for each of the table views.
The functionality works fine and we can retrieve the data correctly but only if the user doesn't change views until the petition is over or the button of the same petition (example: Login button) is pressed on again. Otherwise, different mistakes can happen. For example, an error message that should only be displayed on the root view of one of the navigation controllers appears on the detailed view and vice versa.
We suspect that the issue is that we are currently handling only a single delegate on the Singleton for the "active view" and that we should change it to support a behavior based on the native Mail app in which you can change views while the data that was asked for in each one of the views keeps loading and updating correctly separately.
We have looked over stackoverflow and other websites and we haven't found a proper methodology to follow. We were considering using an NSOperationQueue and wrapping the NSURLConnections on an NSOperation, but we are not sure if that's the proper approach.
Does anyone have any suggestions on the proper way to handle multiple asynchronous NSURLConnections to update multiple views, both parent and child, almost simultaneously at the whim of the user's interaction? Ideally, we don't want to block the UI or disable the buttons as we have been recommended.
Thank you for your time!
Edit - forgot to add, one of the project restrictions set by our client is that we can only use the native iOS sdk network framework and not the ASIHTTPRequest framework or similar. At the same time, we also forgot to add that we are not uploading any information, we are only retrieving it from the WS.
One suggestion is to use NSOperations and a NSOperationsQueue. The nice thing about this arrangement is you can quickly cancel any in-process or queued work (if say the user hits the back button.
There is a project on github, NSOperation-WebFetches-MadeEasy that makes this about as painless as it can be. You incorporate one class in your classes - OperationsRunner - which comes with a "how-to-use-me" in OperationsRunner.h, and two skeleton NSOperations classes, one the subclass of another, with the subclass showing how to fetch an image.
I'm sure others will post of other solutions - its almost a problem getting started as there are a huge number of libraries and projects doing this. That said, OperationsRunner is a bit over 100 lines of code, and the operations about the same, so this is really easy to read, understand, use, and modify.
You say that your singleton has a delegate. Delegation is inappropriate when multiple objects are interested in the result. If you wish to continue using a singleton for fetching data, you must switch your pattern to be based on notifications. Your singleton will have responsibility for determining which connection corresponds to which task, and choosing an appropriate notification to be posted.
If you still need help with this, let me know, I'll try to post some sample code.
I have integrated mobile analytics in my iPhone app with the help of the Flurry analytics but I am not able to track page views.
I have used the following code in my Application Delegate and passed an instance of UINavigationController in the place of navigationController
[FlurryAPI logAllPageViews:navigationController];
But while checking the Page views in the Flurry website it is showing the message like this:
You are not currently tracking Page View data.
Is there something that I have to enable in the flurry website itself?
Good that you now see your data.
On the page count:
Flurry Analytics SDK just counts the number of page views. If you want to see what pages in your app the user visits, i suggest creating events for each of your screens. The user paths report in the events section of your dashboard will then give you a clear path of how your users move around in your app.
"logAllPageViews" method increments the page view count for a session based on traversing a UINavigationController or UITabBarController. If you want to track screens with screen name then just use logEvent method of FlurryAnalytics class like
[FlurryAnalytics logEvent:#"screen name"];
source (check for logAllPageVeiws and logPageView):
http://support.flurry.com/sdkdocs/iOS/interface_flurry_analytics.html#adb7d3bd888a40343269c53f65acf7720
If this question is still open or relevant, you may want to make sure you are adding the navigationController that is in charge of your navigation. Try posting some code with your questions will provide better answers.
It also takes a little bit of time to see results posted to Flurry.
The other benefit of using events is that they are logged within minutes, showing up in the event logs of Flurry well before being accumulated into the summaries. This fast turnaround might prove vital to debugging, as described below.
Note one other gotcha if you fail to see anything, in the case of using iOS I was running many tests and not even events were showing up.
It turned out the code was initialising with
[Flurry setSessionSReportsOnPauseEnabled:NO];
[Flurry setSessionSReportsOnCloseEnabled:NO];
These supposedly buffer your flurry details until the start of the next session. However, some side-effect of debugging meant that the buffering wasn't preserved so my events were never being despatched.
(I inherited a large codebase recently so am still being surprised by things like this.)
You may also use Localytics for this purpose: http://www.localytics.com unlike the other services mentioned you will see your results immediately so you can integrate, test and be done with this process in less than 10 minutes.
The easiest way to track page views with Localytics is to tag an event, when each page is loaded. You can do that with a single API call (modified version of the example in the docs: http://wiki.localytics.com/doku.php?id=iphone_ios4_integration) To track a page the code is:
[[LocalyticsSession sharedLocalyticsSession] tagEvent:#"Start Page"];
Another clever thing you should do is, add an event in your applicationWillEnterBackground which tags an 'app exit' event which records what screen the user was on:
NSDictionary *dictionary =
[NSDictionary dictionaryWithObjectsAndKeys:
#"exit screen",
current_screen_name,
nil];
[[LocalyticsSession sharedLocalyticsSession] tagEvent:#"Leaving App", attributes:dictionary];
This way you can quickly see a distribution of your most common exit pages.
I've decided to integrate OpenFeint into my new game to have achievements and leaderboards.
The game is dynamic and I would like user to be rewarded immediately for some successful results, but as it seems for me, OpenFeint's achievements are a bit sluggish and it shows visual notification only when it receives confirmation from the server.
Is it possible to change something in settings or hack it a little bit to show notification immediately as soon as it checks only local database if the achievement has not been unlocked it?
Not sure if this relates to the Android version of the SDK (which seems even slower), but we couldn't figure out how to make it faster. It was so unacceptably slow that we started developing our own framework that fixes most of open feint's shortcomings and then some. Check out Swarm, it might fit your needs better.
There are several things you can do to more tightly control the timing of these notifications. I'll explain one approach and you can use this as a starting point to explore further on your own. These suggestions apply specifically to iOS apps. One caveat is that these suggestions refer to internal APIs in OFSDK 2.8 for iOS and not ordinarily recommended for high level use and subject to change in future versions.
The first thing I recommend is that you build the sample app with your own product key. Use the standard sample app to experiment before applying the result to your own code.
You are going to get the snappiest response by separating the notification pop-up UI from the process of submitting the achievement. This way you don't have to worry about getting wrapped up in the logic for deciding whether the submission is going just to the local db or is doing the full confirmation on an async network transaction.
See the declaration of "showAchievementNotice" in "OFNotification.h". Performing a search in the sample app, you will see that this is the internal API used for displaying the achievement pop-up when an achievement is earned. It does not actually submit the achievement. You can call this method directly as it is called from "OFAchievementService.mm" to directly control when the message appears. You can then use the following article to disable the pop-up from being called when the actual submission occurs:
http://support.openfeint.com/dev/notification-pop-ups-in-ios/
This gives you complete freedom to call the submission at a later time provided you keep track of the need to do so. For example, you could locally serialize a flag to take care of the actual submission either after the level is done or the next time the app starts up. Don't forget that the user could quit out of a game without cleanly finishing a level.
I'd like to integrate something like a welcome panel (welcome screen) into our iPhone application to inform our users about updates and new offers when they launch the application. I have the following thoughts and doubts:
No user input required
Shows generic HTML without any action from the user point of view, the thing closes after 2 or 3 secs and has a close button if you want to close it manually. This is for advertising and tips.
This should be very simple to implement
User input required
Shows generic HTML with an action required from the user point of view, for example a survey. The user should be able to skip it
same as above, but is it possible that the user submits something on a HTML page and that causes also something to happen within the iPhone app (maybe via Java Script)? For example the user submits a survey on the HTML page and then app closes the current screen and continues to the next screen (i.e. the real application)?
Is it also possible to receive parameters (e.g. an ID) via a HTML website? e.g. if the user receives an offer on the HTML welcome panel, then he clicks on it and it takes him directly to a screen in the iPhone app with content loaded from a server (via JSON) depening on the offer id retrieved through the HTML page.
We prefer implementing it via HTML, because it gives us more flexibility. But I'm also open to hear other suggestions.
Thanks
Rengers answer is the correct one to accomplish what you want. However, the real correct answer is "Don't do that in the first place."
From a design perspective, a "Welcome Panel" or any kind of startup/splash-screen is a bad idea and the Apple Documentation tells you explicitly not to use them. Even for games, they're a bad idea that should be avoided if possible.
It's not a "Welcome Panel" it's a "wade-through-all-our-marketing-crap-before-you-can-actually-use-our-app" panel.
Mobile apps aren't like apps for regular platforms. Non-mobile hardware is faster so the obtrusive startup screens load faster and can be dismissed faster. Non-mobile apps tend to accomplish many task and people use them sitting down for prolonged periods. Users will tolerate a few seconds wasted clicking through startup screens so they can get into an app they will use for many minutes or even hours.
By contrast, mobile apps are often used by people on the go and in a hurry. The apps are small and ideally perform a single task. As quickly as possible, people need to be able to get into the app, perform what ever task the app accomplishes and then get back out again. If you're only using an app each time for 30 seconds or so, having to spend 5 seconds each time wading through startup screens is massively annoying.
Mobil hardware is slower and operations can take longer. Depending on its complexity and resources an app can take as much as 10 seconds to launch. In your case you want to add to a startup screen that has to load, connect to a url, display and then have the user perform an operation. That will take another 5-10 seconds minimum. So you're looking at users having to spend 20 seconds or more just getting into your app.
That doesn't sound like much but try mocking up your app and then using it on the go i.e. while walking, waiting for an elevator, going up the stairs, waiting for a red light etc. Test it in social situations. In the middle of conversation say, "Let me check on that" then take out the iPhone launch your app and try to get some information from it. 20 seconds becomes a very long time in all these circumstances.
Even shorter launch times are very annoying if you have to take some action every single time you open the app just to get to the functional part of the app. It's arguably even worse to spring a startup screen on them intermittently so they never know when they open your app how long it will take to get in it. User surprise is not good design.
Instead of forcing users to do something, you should embed advertisements and update notices unobtrusively in the app itself so that people can see them while they are using the app. In the case of advertising, this has the added advantage of putting the adds in view the entire time the user is looking at the app.
I don't know how many times some idiot from marketing has come in and started a feature request with, "We need to force the user to..." The only response to those types of request is to set the marketing weeny on fire. Do that several times and they'll stop trying to systematically alienate your customers.
UIWebViewDelegate has a method that allows you to respond to interaction in a HTML page:
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
Using this, you can catch any links clicked and respond to them in your application by presenting a different view.
Recieving parameters like an id can be done in a few different ways.
1) You can parse the HTML and determine it from the source.
2) You can have a javascript function in the HTML that returns the id. Call it by using
- (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script
3) You can also use the delegate method I mentioned.
If you make a link like this: get offer you can catch it in the delegate and retrieve the id from the NSURLRequest.
I hope this will point you in the right direction.
If you do need some kind of startup screen a good option is to use the default.png. The app loads and displays that image before it does anything else.
It's usually used to display the illusion of the user interface before the UI loads completely. However, you could use it to display startup information. Since it displays almost instantly (within 1 sec) it does give your user something to look at while the app loads. In the case of a mock interface, it lets the user see the location of the interface elements and begin moving to activate them before the elements finish loading.
The catch is that the image disappears as soon as the first view loads so you have to load a view behind it that is a duplicate of the image (more ofter the image is screenshot of the view)
In your case you would need to dynamically generate the default.png when the web page updated. Upon launch it would display the information and buy the time the user read it, made a decision and touched the interface, the real web page would have replaced it.
Of course, this system won't work if you want new info at the start of each launch. Instead you'll have to generate the image during one run for use in the next.
In any case, if you launch into a web page the user did not select, I advise that you create a default.png that displays a message along the lines of "Checking for Updates and Info" (or whatever your doing) so the user won't think your app launched and hung.