A little background:
I developed a game in Libgdx and upload it to iTunes app store. My app got rejected with a following reason: (This is not the question but I would like to give you a little background of what I am trying to achieve)
> 17.1 Details
Additionally, we noticed that your app does not obtain user consent before collecting the user's personal data.
Specifically, users scores are posted to a high score feature. Please see the attached screenshot(s) for additional information.
Next Steps
To collect personal data with your app, you must make it clear to the user that their personal data will be uploaded to your server and you must obtain the user's consent before the data is uploaded.
- Starting with iOS 6, there are keys for specifying the reason the app will access the user's protected data. When the access prompt is displayed, the purpose specified in these keys is displayed in that dialog box. If your application will be transmitting protected user data, the usage string in your access request should clearly inform the user that their data will be uploaded to your server if they consent.
My app only upload high score to my server. But okay if Apple states that the user should know about this I will make it clear.
Actual mission:
I dont know anything about objective-c programming since I made this app in Java. But I know that iOS have some security dialogs which prompts the user if they are Okay to use the following feature or data in the app.
I would like to invoke this kind of dialog (with my own message)
I also know that it should be defined in my info.plist file, but I dont know how to access it at runtime and show it in my game.
Does somebody have a clue how to open this up?
You could try my libgdx extension for dialog windows: https://github.com/TomGrill/gdx-dialogs
or:
You need to interface with platform specifig code: https://github.com/libgdx/libgdx/wiki/Interfacing-with-platform-specific-code
Use UIAlertView class in your iOS interface implementation to open an AlertView:
Code example:
UIAlertViewDelegateAdapter delegate = new UIAlertViewDelegateAdapter() {
#Override
public void didDismiss(UIAlertView alertView, long buttonIndex) {
//handle button click based on buttonIndex
}
#Override
public void clicked(UIAlertView alertView, long buttonIndex) {
}
#Override
public void cancel(UIAlertView alertView) {
}
#Override
public void willPresent(UIAlertView alertView) {
}
#Override
public void didPresent(UIAlertView alertView) {
}
#Override
public void willDismiss(UIAlertView alertView, long buttonIndex) {
}
#Override
public boolean shouldEnableFirstOtherButton(UIAlertView alertView) {
return false;
}
};
String[] otherButtons = new String[1];
otherButtons[0] = "No";
String firstButton = "Yes";
UIAlertView alertView = new UIAlertView("Title", "message", delegate, firstButton, otherButtons);
alertView.show();
Related
I'm building a prototype using Vaadin8 starting from a single-module template.
I'm trying to assign a unique UI instance (a session) to each authenticated user, so that each user is presented with a particular type of content according to their own settings within the app. Here's my configuration:
#WebListener
public class Market implements ServletContextListener {
public static ArrayList<User>users;
public void contextInitialized(ServletContextEvent sce) {
users=new ArrayList<User>();
User hau=new User("hau");
users.add(hau);
User moc=new User("moc");
users.add(moc);
}
public void contextDestroyed(ServletContextEvent sce){}
}
public class User {
public String username;
public user(String username){this.username=username;}
}
public class MyUI extends UI {
User us3r;
#Override
protected void init(VaadinRequest vaadinRequest) {
final VerticalLayout layout = new VerticalLayout();
String username;
if (this.us3r==null) {username="Guest";}else {username=us3r.username;}
Label who=new Label(username);
TextField userfield=new TextField();
Button login=new Button("login");
login.addClickListener(new ClickListener() {
#Override
public void buttonClick(ClickEvent event) {
for (User user:Market.users) {
if (userfield.getValue().equals(user.username)) {
us3r=user;Page.getCurrent().reload();return;
}
}Notification.show("No user "+userfield.getValue());
}
});
Button logout=new Button("logout");
logout.addClickListener(new ClickListener() {
public void buttonClick(ClickEvent event) {
if(us3r!=null) {us3r=null; Page.getCurrent().reload();}
}
});
layout.addComponent(userfield);
layout.addComponent(login);
layout.addComponent(who);
layout.addComponent(logout);
setContent(layout);
}
After inputting one of the two usernames registered in the Database, I'd like the Label object to display the name of the authenticated user, instead of "Guest". Another effect I'm trying to achieve is if a user is logged in and there is another request to the server, it should generate a fresh UI with the uninstantiated us3r attribute.
Caveats: I have been using Vaadin Flow lately rather than Vaadin 8. So my memory is hazy, and my code may be wrong. And I have kept all the examples overly simple, not ready for production. Lastly, I am sure others would take a different approach, so you may want to do some internet searching to see alternatives.
UI is malleable
The UI of Vaadin is more plastic and malleable than you may realize. You can entirely replace the initial VerticalLayout with some other widget-containing-view.
The way I have handled logins with Vaadin is that my default UI subclass checks for an object of my own User class in the web session. Being based on Jakarta Servlet technology, every Vaadin web app automatically benefits from the Servlet-based session handling provided by the Servlet container. Furthermore, Vaadin wraps those as a VaadinSession.
If the User object is found to be existing as an "attribute" (key-value pair) in the session, then I know the user has already logged-in successfully. So I display the main content in that initial UI subclass object. By "main content", I mean an instance of a particular class I wrote that extends VertialLayout, or HoriontalLayout or some such.
If no User object is found, then my initial UI subclass object displays a login view. By "login view" I mean an instance of some other particular class I wrote that extends VertialLayout, or HoriontalLayout or some such.
When you switch or morph the content within a UI subclass instance, Vaadin takes care of all the updating of the client. The change in state of your UI object on the server made by your Java code is automatically communicated to the Vaadin JavaScript library that was initially installed in the web browser. That Vaadin JS
library automatically renders your changed user-interface by generating the needed HTML, CSS, JavaScript, and so on. There is no need for you to be reloading the page as you seem to be doing in your example code. As a single-page web app, the web page only loads once. In Vaadin, we largely forget about the HTTP Request/Response cycle.
Example app
First we need a simple User class for demonstration purposes.
package work.basil.example;
import java.time.Instant;
import java.util.Objects;
public class User
{
private String name;
private Instant whenAuthenticated;
public User ( String name )
{
Objects.requireNonNull( name );
if ( name.isEmpty() || name.isBlank() ) { throw new IllegalArgumentException( "The user name is empty or blank. Message # b2ec1529-47aa-47c1-9702-c2b2689753cd." ); }
this.name = name;
this.whenAuthenticated = Instant.now();
}
#Override
public boolean equals ( Object o )
{
if ( this == o ) return true;
if ( o == null || getClass() != o.getClass() ) return false;
User user = ( User ) o;
return name.equals( user.name );
}
#Override
public int hashCode ( )
{
return Objects.hash( name );
}
}
The starting point of our app, our subclass of UI checks the session and switches content. Notice how we segregated the check-and-switch code to a named method, ShowLoginOrContent. This allows us to invoke that code again after login, and again after logout.
package work.basil.example;
import com.vaadin.annotations.Theme;
import com.vaadin.annotations.VaadinServletConfiguration;
import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinServlet;
import com.vaadin.server.VaadinSession;
import com.vaadin.ui.UI;
import javax.servlet.annotation.WebServlet;
import java.util.Objects;
/**
* This UI is the application entry point. A UI may either represent a browser window
* (or tab) or some part of an HTML page where a Vaadin application is embedded.
* <p>
* The UI is initialized using {#link #init(VaadinRequest)}. This method is intended to be
* overridden to add component to the user interface and initialize non-component functionality.
*/
#Theme ( "mytheme" )
public class MyUI extends UI
{
#Override
protected void init ( VaadinRequest vaadinRequest )
{
this.showLoginOrContent();
}
void showLoginOrContent ( )
{
// Check for User object in session, indicating the user is currently logged-in.
User user = VaadinSession.getCurrent().getAttribute( User.class );
if ( Objects.isNull( user ) )
{
LoginView loginView = new LoginView();
this.setContent( loginView );
} else
{
CustomerListingView customerListingView = new CustomerListingView();
this.setContent( customerListingView );
}
}
#WebServlet ( urlPatterns = "/*", name = "MyUIServlet", asyncSupported = true )
#VaadinServletConfiguration ( ui = MyUI.class, productionMode = false )
public static class MyUIServlet extends VaadinServlet
{
}
}
Here is that LoginView, a VerticalLayout. We have our username & password, with a "Sign in" button. Notice how on successful authentication we:
Instantiate a User and add to the automatically-created session as an "attribute" key-value pair. The key is the class User, and the value is the User instance. Alternatively, you can choose to use a String as the key.
Invoke that showLoginOrContent method on MyUI to swap out our login view with a main content view.
In real work, I would locate the user-authentication mechanism to its own class unrelated to the user-interface. But here we ignore the process of authentication for this demonstration.
package work.basil.example;
import com.vaadin.server.VaadinSession;
import com.vaadin.ui.*;
public class LoginView extends VerticalLayout
{
private TextField userNameField;
private PasswordField passwordField;
private Button authenticateButton;
public LoginView ( )
{
// Widgets
this.userNameField = new TextField();
this.userNameField.setCaption( "User-account name:" );
this.passwordField = new PasswordField();
this.passwordField.setCaption( "Passphrase:" );
this.authenticateButton = new Button( "Sign in" );
this.authenticateButton.addClickListener( ( Button.ClickListener ) clickEvent -> {
// Verify user inputs, not null, not empty, not blank.
// Do the work to authenticate the user.
User user = new User( this.userNameField.getValue() );
VaadinSession.getCurrent().setAttribute( User.class , user );
( ( MyUI ) UI.getCurrent() ).showLoginOrContent(); // Switch out the content in our `UI` subclass instance.
}
);
// Arrange
this.addComponents( this.userNameField , this.passwordField , this.authenticateButton );
}
}
Lastly, we need our main content view. Here we use a "customer listing" that is not yet actually built. Instead, we place a couple pieces of text so you know the layout is appearing. Notice how in this code we look up the user's name from our User object in the session attribute.
We include a "Sign out" button to show how we reverse the authentication simply by clearing our User instance as the value of our "attribute" on the session. Alternatively, you could kill the entire session by calling VaadinSession::close. Which is appropriate depends on your specific app.
package work.basil.example;
import com.vaadin.server.VaadinSession;
import com.vaadin.ui.Button;
import com.vaadin.ui.Label;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;
import java.time.Duration;
import java.time.Instant;
public class CustomerListingView extends VerticalLayout
{
Button logoutButton;
public CustomerListingView ( )
{
// Widgets
this.logoutButton = new Button( "Sign out" );
this.logoutButton.addClickListener( ( Button.ClickListener ) clickEvent -> {
VaadinSession.getCurrent().setAttribute( User.class , null ); // Pass null to clear the value.
( ( MyUI ) UI.getCurrent() ).showLoginOrContent();
}
);
User user = VaadinSession.getCurrent().getAttribute( User.class );
Duration duration = Duration.between( user.getWhenAuthenticated() , Instant.now() );
Label welcome = new Label( "Bonjour, " + user.getName() + ". You’ve been signed in for: " + duration.toString() + "." );
Label placeholder = new Label( "This view is under construction. A table of customers will appear here.\"" );
// Arrange
this.addComponents( this.logoutButton , welcome , placeholder );
}
}
The effect of the "Sign out" button is to remove the main content, and take the user back to the login view.
Separation of concerns
One of the aims of the approach to logins is separation of concerns. The concern of building an interactive user-interface (Vaadin widgets and code) should be kept largely separate from the business logic of how we determine if a user is who they claim to be (authentication code).
Our UI subclass knows almost nothing about user-authentication. We moved all the mechanics of logging-in to other non-Vaadin-specific classes. The Vaadin-related code only has two connection points to authentication: (a) Passing collected credentials (username, password, or such), and (b) Checking for the presence of a User object in the session’s key-value store.
Multi-window web apps
By the way, you should know that Vaadin 8 has amazing support for multi-window web apps. You can write links or buttons to open additional windows/tabs in the browser, all working within the same web app and the same user session. Each tab/window has its own instance of a UI subclass you wrote. All of these UI subclass instances share the same VaadinSession object.
So using the logic seen above applies to all such tab/windows: Multiple windows all belonging to one session with one login.
Fake dialog boxes are not secure
You might be tempted to put your login view inside a dialog box appearing over your main content. Do not do this. A web dialog box is “fake”, in that it is not a window created and operated by the operating-system. A web app dialog window is just some graphics to create the illusion of a second window. The pretend dialog and the underlying content are actually all one web page.
A hacker might gain access to the content on the page, and might be able to defeat your login dialog. This is mentioned in the Vaadin manual, on the page Sub-Windows.
In my example above, we have no such security problem. The sensitive main content arrives on the user’s web browser only after authentication completes.
Web app lifecycle hooks
By the way, your use of ServletContextListener is correct. That is the standard hook for the lifecycle of your web app launching. That listener is guaranteed to run before the first user’s request arrives, and again after the last user’s response is sent. This is an appropriate place to configure resources needed by your app in general, across various users.
However, in Vaadin, you have an alternative. Vaadin provides the VaadinServiceInitListener for you to implement. This may be more convenient than the standard approach, though you need to configure it by creating a file to make your implementation available via the Java Service Implementation Interface (SPI) facility. Your VaadinServiceInitListener as another place to setup resources for your entire web app. You can also register further listeners for the service (web app) shutting down, and for user-session starting or stopping.
Browser Reload button
One last tip: You may want to use the #PreserveOnRefresh annotation.
Vaadin Flow
In Vaadin Flow (versions 10+), I take the same approach to logins.
Well, basically the same. In Vaadin Flow, the purpose of the UI class was dramatically revamped. Actually, that class should have been renamed given how differently it behaves. We no longer routinely write a subclass of UI when starting a Vaadin app. A UI instance is no longer stable during the user's session. The Vaadin runtime will replace the UI object by another new instance (or re-initialize it), sometimes quite rapidly, for reasons I do not yet understand. So I do not see much practical use for UI for those of us writing Vaadin apps.
Now in Flow I start with an empty layout, instead of a UI subclass. Inside that layout I swap nested layouts. First the login view. After authentication, I swap the login view for the main content view. On logout, the opposite (or close the VaadinSession object).
Is there a way to achieve deep linking in a flutter, so that if a user clicks on a link then they are redirected to a specific part of the app, given that the app is installed, but if it isn't, they are redirected to the respective app store, to install the application and then taken to that specific part?
While searching for a solution I came across this package called uni_links but I am not sure if it can fulfill this requirement.
You can use Firebase dynamic links for this purpose:
https://firebase.google.com/docs/dynamic-links
There it says:
if a user opens a Dynamic Link on iOS or Android and doesn't have
your app installed, the user can be prompted to install it; then,
after installation, your app starts and can access the link.
You can find information on how to implement this with Flutter here:
https://pub.dev/packages/firebase_dynamic_links
I have tried it myself with Android and iOS and it worked fine. If the app is not installed, the Google Play store or Apple AppStore is opened. The user can tap "Install" and then "Open". Afterward your app is started and the dynamic link is sent to your app (on iOS via the clipboard) where you can access it as explained on the website above. I.e. right after the start of your app in the first initState method you can call
final PendingDynamicLinkData data = await FirebaseDynamicLinks.instance.retrieveDynamicLink();
final Uri deepLink = data?.link;
to get the deep link. However in my experience on iOS this is too early to retrieve the link. I got "null" when trying it. It seemed to take a moment. I then used a WidgetsBindingObserver and watched in the didChangeAppLifecycleState method for AppLifecycleState.resumed. There I called retrieveDynamicLink. Due to a permission request (if the user allows notifications) the method was called twice. The first time it returned null but when it was called the second time it returned the deep link. So my solution looks like this:
class _MyHomePageState extends State<MyHomePage> with WidgetsBindingObserver {
#override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
#override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
#override
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.resumed) {
_retrieveDynamicLink();
}
}
/**
* Laden des Deep Link nach der Installation.
*/
Future<void> _retrieveDynamicLink() async {
final PendingDynamicLinkData data = await FirebaseDynamicLinks.instance.retrieveDynamicLink();
final Uri deepLink = data?.link;
if (deepLink != null) {
// Use the deepLink
// ...
}
}
As of iOS 12 there is no way to have a direct application deep link that redirects to the app store if your application is not installed.
You can have a deep link to the app store or a deep link within your app using the meta tag apple-itunes-app on a website. But this only shows a small banner at the top of the page, and is not a true deep link.
One system that I haven't used before but might be worth checking out as well is branch.io. You might be able to achieve something like that with their system, but I'm not exactly sure how it works. It for sure is not native as part of iOS 12.
I am answering late but it will might help to others.
We can use firebase dynamic links for deep linking in a flutter with firebase_dynamic_links plugin. Refer this link for full implementation steps and create and receive a link, https://medium.com/better-programming/deep-linking-in-flutter-with-firebase-dynamic-links-8a4b1981e1eb. Here is a sample code for receiving a link inside the app and open a specific screen.
class MainWidgetState extends State<MainWidget> {
#override
void initState() {
super.initState();
this.initDynamicLinks();
}
initDynamicLinks(BuildContext context) async {
await Future.delayed(Duration(seconds: 3));
var data = await FirebaseDynamicLinks.instance.getInitialLink();
var deepLink = data?.link;
final queryParams = deepLink.queryParameters;
if (queryParams.length > 0) {
var userName = queryParams['userId'];
openSpecificScreen(userName);
}
FirebaseDynamicLinks.instance.onLink(onSuccess: (dynamicLink)
async {
var deepLink = dynamicLink?.link;
final queryParams = deepLink.queryParameters;
if (queryParams.length > 0) {
var userName = queryParams['userId'];
openSpecificScreen(userName);
}
debugPrint('DynamicLinks onLink $deepLink');
}, onError: (e) async {
debugPrint('DynamicLinks onError $e');
});
}
openSpecificScreen(String userName){
Navigator.of(context).pushNamed("routeFormScreen", arguments: {"name": userName});
}
}
I am using Xamarin.Form to write a Android app. I have successfully implemented the OAuth and I can sign in and get the user information using OAuth2Authenticator.
When the user clicks signup/Login I show the OAuthLoginPresenter as follows:
var oAuthLoginPresenter = new Xamarin.Auth.Presenters.OAuthLoginPresenter();
oAuthLoginPresenter.Login(App.OAuth2Authenticator);
This works great and the user sees the login page.
When the user clicks Allow the completed Event on the OAuth2Authenticator instance fires as expected and the user is once again back looking at the app.
However this is where my problem is - I get a notification:
If CustomTabs Login Screen does not close automatically close
CustomTabs by Navigating back to the app.
Thing is though I am back at the app. If I look at all my open apps I can see the login screen is still running in the back ground so that presenter has not closed.
In my intercept Activity which gets the redirect looks like this:
[Activity(Label = "GoogleAuthInterceptor")]
[IntentFilter
(
actions: new[] { Intent.ActionView },
Categories = new[]
{
Intent.CategoryDefault,
Intent.CategoryBrowsable
},
DataSchemes = new[]
{
// First part of the redirect url (Package name)
"com.myapp.platform"
},
DataPaths = new[]
{
// Second part of the redirect url (Path)
"/oauth2redirect"
}
)]
public class GoogleAuthInterceptor: Activity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Create your application here
Android.Net.Uri uri_android = Intent.Data;
// Convert Android Url to C#/netxf/BCL System.Uri
Uri uri_netfx = new Uri(uri_android.ToString());
// Send the URI to the Authenticator for continuation
App.OAuth2Authenticator?.OnPageLoading(uri_netfx);
Finish();
}
}
Am I missing a step in here to close that presenter? Any other ideas please?
UPDATE:
I have now found that using Chrome as the default browser works fine and presenter is closed. But if I use a Samsung browser as my default browser - it does not close.
So I need a way to close it manually.
Just set property to null when initializing Xamarin.Auth in your main activity:
//don't show warning message when closing account selection page
CustomTabsConfiguration.CustomTabsClosingMessage = null;
My Vaadin 7 application doesn't react on browser url changing. For example I entering from keyboard a new url parameters and pressing Enter key and after that nothing is changing.
Application only reacts on F5 or page refresh button.
How to also make Vaadin 7 application to respond to Enter key after url update ?
UPDATED
I'm using Vaadin com.vaadin.navigator.Navigator object.
For example I have an url: http://example.com/#!products/30970
When I change the url in browser address bar (for example to http://example.com/#!products/34894) and press enter key I would like to change information at my page in order to show info about product with id 34894 instead of product with a previous id 30970.
Vaadin Navigator and UriFragmentChangedListener
Right now I'm using Vaadin Navigator in order to define views:
Navigator navigator = new Navigator(this, viewDisplay);
navigator.addView("products", ProductView.class);
First time in web browser I'm successfully able to access this view with product id parameter for example by the following url:
http://example.com/#!products/30970
ProductView is constructed first time and in its public void enter(ViewChangeListener.ViewChangeEvent event) method I'm able to get uri parameters.
But after that when I change product id in web browser address bar in this url to another one(for example to 30971 in order to display information for another product):
http://example.com/#!products/30971
and press Enter key the view is not refreshed and doesn't react on these changes..
As suggested in the comments I have added UriFragmentChangedListener listener and now at least able to handle URL fragment changes(after Enter key presing).
Now, my logic have to react on these changes and I'm looking for a correct way how it should be implemented in Vaadin 7.
So, If I understood correctly - in additional to Navigator logic I also have to use this listener and inside of this listener logic I have to get a reference on appropriate view(navigator.getCurrentView() ?) object and invoke some method on this object in order to change internal view state without full view rebuild ? If I'm correct - is there some standard mechanism in Vaadin in order to simplify this job ?
i can not think of another way than pass the UriFragmentChangeEvent manually to your View. I guess the Vaadin API can not do it automatic.
public class MyUI extends UI{
#Override
protected void init(final VaadinRequest request) {
/*
* UriFragmentChangedListener
* when URL+Parameter manuell eingegeben werden
*/
getPage().addUriFragmentChangedListener(new UriFragmentChangedListener() {
#Override
public void uriFragmentChanged(UriFragmentChangedEvent event) {
View currentView = getNavigator().getCurrentView();
if(currentView != null){
if(currentView instanceof UriFragmentChangedListener){
((UriFragmentChangedListener)currentView).uriFragmentChanged(event); //custom method
}
}
}
});
}
}
To make this work add UriFragmentChangedListener to your ProductView:
public class ProductView extends CustomComponent implements View, UriFragmentChangedListener {
}
take a look at the Parameters in the ViewChangeEvent of your ProductView
By using this url structure "http://example.com/#!products/30970", you can read the product id as following:
#Override
public void enter(ViewChangeEvent event) {
String productId = event.getParameters();
}
I can not be more clear with the title :D
Is it possible? to launch an application on a blackbeery just cliking on a "link" inside a mail? i read about taping a url and going to the application but this is much more specific.
thx in advance
Actually you can listen incoming emails.
You can implement menu item that will be available in mail app.
But you can also implement content handler with specific URI to launch your app.
All examples are available in BB samples.
Look in the RIM sample apps, more specifically HTTPFilterDemo.
You have to register a filter for the type of link you need the app to be triggered by (you'll need to put this code in the main method of you app):
HttpFilterRegistry.registerFilter("www.rim.com","com.rim.samples.device.httpfilterdemo.filter");
where "www.rim.com" is obviously the link that should open the app and the second parameter is the package that contains the "Protocol" class. The Protocol class has a callback method:
public Connection openFilter( String name, int mode, boolean timeouts ) throws IOException {
This method will be called each time the user clicks on a link that has the form specified by you. So, to open the app, in the "openFilter" method, do:
int modHandle = CodeModuleManager.getModuleHandle("YourAppModuleName");
ApplicationDescriptor[] apDes = CodeModuleManager.getApplicationDescriptors(modHandle);
try {
ApplicationManager.getApplicationManager().runApplication(apDes[0]);
} catch (ApplicationManagerException e) {
e.printStackTrace();
}