codingdir logo sitemap sitemap |
Home
PHP
C#
C++
ANDROID
JAVA
JAVASCRIPT
PYTHON

WebView Twitter login window on UI thread


By : , Category : android

Yes, using the ScrictMode Policy is a hack, and a terrible one as stated here and here

You have two ways to solve this:

1- Return the authURL from the onPostExecute() method of your MyLoginTask. Simply define a setter in the object that calls the MyLoginTask, and have onPostExecute() assign the result to it.

2- Pass a reference to your webview to the MyLoginTask, and have it load the url in the onPostExecute(). Because onPostExecute() will always run in the UI thread, you will get rid of the warning.

In any case, do check out this post by the Android developers about 'Painless Threading'; you will certainly find it helpful: http://android-developers.blogspot.ca/2009/05/painless-threading.html

ReLated :

Strp 1:

In loginToTwitter() do like this:

if (!isLoggedIn) {
        final ConfigurationBuilder builder = new ConfigurationBuilder();
        builder.setOAuthConsumerKey(consumerKey);
        builder.setOAuthConsumerSecret(consumerSecret);

        final Configuration configuration = builder.build();
        final TwitterFactory factory = new TwitterFactory(configuration);
        twitter = factory.getInstance();

        try {
            requestToken = twitter.getOAuthRequestToken(callbackUrl);

            final Intent intent = new Intent(getActivity(), WebViewActivity.class);
            intent.putExtra(WebViewActivity.EXTRA_URL, requestToken.getAuthenticationURL());
            startActivityForResult(intent, WEBVIEW_REQUEST_CODE);

        } catch (TwitterException e) {
            e.printStackTrace();
        }
    }

Step 2:

And create webviewclient by extend WebViewClient in WebViewActivity like here

Step 3:

And implement 'onActivityResult' in your main activity like:

if (requestCode == WEBVIEW_REQUEST_CODE) {
        try {
            String verifier = data.getExtras().getString(oAuthVerifier);
            AccessToken accessToken = twitter.getOAuthAccessToken(requestToken, verifier);

            long userID = accessToken.getUserId();
            final User user = twitter.showUser(userID);
            String username = user.getName();

            saveTwitterInfo(accessToken);
            String id = mSharedPreferences.getString(WSKeys.TwitterClass.PREF_USER_ID, "");
            String name = mSharedPreferences.getString(WSKeys.TwitterClass.PREF_USER_NAME, "");
            wscallSocialSignIn("", id, accessToken.toString(), name, image, "Twitter");
        } catch (Exception exception) {

        }
    }

After about 5 days of trying out new methods like isolating the facebook login authentication to its own Activity with its own set of fragments which also failed to behave the way it should, I read up on the Fragments Documentation which gave me a better understanding on how fragments actually work and are meant to work. For anyone facing a similar issue as me, I highly recommend you read up the documentation first.

The FragmentManager or rather the SupportFragmentManager which I use, together with the method beginTransaction(), exposes the method called replace() which will allow you to replace the fragment in the current view with the one you want to display. Here's how i use it:

  public void replaceFragment(Fragment f, Boolean addToBackStack) {
        if (addToBackStack) {
            getSupportFragmentManager().beginTransaction()
                    .replace(android.R.id.content, f).addToBackStack(null).commit();
        } else {
            getSupportFragmentManager().beginTransaction()
                    .replace(android.R.id.content, f).commit();
        }
    }

The addToBackStack parameter is for you to decide if the user can navigate back to that fragment after you show the new one.

So instead of using the showFragment() that is shown in the Facebook Android API examples, I replaced all of the showFragment() methods with replaceFragment().

The differece between the 2 is that, when you use the showFragment() method whereby you pre-load all the fragments in your Host Activity (In my case LoginActivity.java) what happens is that ALL the fragment's onCreate(), onStart() and onResume() functions are called. This behaviour was bad as some of my fragments started carrying out the code in the onStart() methods causing all the progressDialogs to show as well when they shouldn't.

By using the replaceFragment() method shown above, I can instantiate the fragment only when I need to show it, allowing me to utilize the lifecycle methods (onCreate(), onStart(), onResume() etc) normally.

After the user has logged in successfully, I simply show the user my menu and clear the back stack with the following method:

public void clearBackStack() {
    FragmentManager manager = getSupportFragmentManager();
    // Get the number of entries in the back stack
    int backStackSize = manager.getBackStackEntryCount();
    // Clear the back stack
    for (int i = 0; i < backStackSize; i++) {
        manager.popBackStack();
    }
}

Key areas to clear the back stack would be after the user has successfully logged in, and when the user has successfully logged out.

With this, I am able to control the fragments better, since they behave like activities in terms of its lifecycle.

Hopefully this would be of some help to someone out there.

----------> Debuger not going here if (granted == YES)

May be you didn't have configure your twitter account in iOS's Settings.

OR you didn't allowed the access of twitter from your app by clicking on Disallow when twitter pop up appeared.

Cross check (Simulator) : Settings->Privacy->Twitter does your app appeared in list ? If not then delete it and try again.

Working code :

    accountStore = [[ACAccountStore alloc] init]; // Declare it in .h file (for testing)
    ACAccountType *twitterAccountType = [accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];
    NSArray *twitterAccounts = [accountStore accountsWithAccountType:twitterAccountType];

    // Runing on iOS 6
    if (NSClassFromString(@"SLComposeViewController") && [SLComposeViewController isAvailableForServiceType:SLServiceTypeTwitter])
    {
        [accountStore requestAccessToAccountsWithType:twitterAccountType options:NULL completion:^(BOOL granted, NSError *error)
         {
             if (granted) // User already login in default Twitter application
             {
             }
         }];
    }

This is what you want ?

Application Helper:

module ApplicationHelper
  def link_to_login_with(provider, url, html_options = {})
    add_default_class(html_options)
    convert_popup_attributes(html_options)

    link_to t('.login_with_link', provider: provider), url, html_options
  end

  private

  def add_default_class(html_options)
    default_class = "js-popup"

    if html_options.has_key?(:class)
      html_options[:class] << " " << default_class
    else
      html_options[:class] = default_class
    end
  end

  def convert_popup_attributes(html_options)
    width = html_options.delete(:width)
    height = html_options.delete(:height)

    if width && height
      html_options[:data] ||= {}
      html_options[:data].merge!({width: width, height: height})
    end
  end
end

Application.html.erb

<!DOCTYPE html>
<html>
<head>
  <title>Omniauth Popup</title>
  <%= stylesheet_link_tag    'application' %>
  <%= javascript_include_tag 'application' %>
  <%= csrf_meta_tags %>
</head>
<body>
  <header class='main'>
    <nav class='user-nav'>
      <ul>
        <% if current_user %>
          <li>
            <%= link_to current_user do %>
              <%= image_tag current_user.image, class: 'user-pic' if current_user.image %>
              <%= content_tag :span, current_user.name %>
            <% end %>
          </li>
          <li><%= link_to t('.logout_link'), sign_out_path %></li>
        <% else %>
          <li><%= link_to_login_with 'Facebook', '/auth/facebook', { width: '460', height: '460' } %></li>
          <li><%= link_to_login_with 'GitHub', '/auth/github', { width: '1050', height: '700' } %></li>
          <li><%= link_to_login_with 'Google', '/auth/google', { width: '800', height: '470' } %></li>
          <li><%= link_to_login_with 'Twitter', "/auth/twitter?lang=#{I18n.locale}", { width: '660', height: '710' } %></li>
        <% end %>
      </ul>
    </nav>
  </header>

  <div id='js-messages' class='messages'>
    <% flash.each do |type, message| %>
      <span class='message <%= type %>'>
        <%= message %>
      </span>
    <% end %>
  </div>

  <div class='content'>
    <%= yield %>
  </div>
</body>
</html>

app/assets/javascripts/login.js

$(document).ready(function() {
    $('.js-popup').click(function() {
        centerPopup($(this).attr('href'), $(this).attr('data-width'), $(this).attr('data-height'));
        return false;
    });
});

function centerPopup(linkUrl, width, height) {
    var sep = (linkUrl.indexOf('?') !== -1) ? '&' : '?',
        url = linkUrl + sep + 'popup=true',
        left = (screen.width - width) / 2 - 16,
        top = (screen.height - height) / 2 - 50,
        windowFeatures = 'menubar=no,toolbar=no,status=no,width=' + width +
            ',height=' + height + ',left=' + left + ',top=' + top;
    return window.open(url, 'authPopup', windowFeatures);
}

Controller

class SessionsController < ApplicationController
  def create
    # Have a look at the info returned by the provider by uncommenting the next line:
    # render text: "<pre>" + env["omniauth.auth"].to_yaml and return
    omniauth = env['omniauth.auth']
    user = User.find_or_create_with_omniauth(omniauth)
    session[:user_id] = user.id
    flash[:notice] = t('controllers.sessions.create', provider: pretty_name(omniauth.provider))
    render_or_redirect
  end

  def failure
    flash[:alert] = t('controllers.sessions.failure', provider: pretty_name(env['omniauth.error.strategy'].name))
    render_or_redirect
  end

  def destroy
    session[:user_id] = nil
    redirect_to root_url, notice: t('controllers.sessions.destroy')
  end

  protected

  def render_or_redirect
    page = env['omniauth.origin']
    if env['omniauth.params']['popup']
      @page = page
      render 'callback', layout: false
    else
      redirect_to page
    end
  end

  def pretty_name(provider_name)
    provider_name.titleize
  end
end

app/views/sessions/callback.html.erb

<%= javascript_tag do %>
  window.opener.location = '<%= @page %>';
  window.close();
<% end %>
Comments


Message :
Login to Add Your Comments .
How to disable registered OpenCL platforms on Windows?
Is Observable broken in Angular 2 Beta 3?
Cross-thread operation not valid when using Invoke
How to pass an IEnumerable or queryable list of properties from Controller to View
Finding numbers after a certain keyword using Python
Pocketsphinx recognizes random phrases in a silence
Passing non-thread-safe objects through thread-safe containers
React scroll nav
BizTalk WCF-BasicHttp Adapter does not allow Empty string for Service Certificate Props
Why property ''cause" of Exception is repeating forever?
Privacy Policy 2017 © codingdir.com All Rights Reserved .