[Twitter API] OAuthのCallback URLホワイトリスト化に対応する

概要

2018/06/12よりTwitter OAuthのCallback URL関係で変更がありました。
この変更に伴い、以下のようなエラーが発生するようになりました。

code: 415
Callback URL not approved for this client application. Approved callback URLs can be adjusted in your application settings.

変更内容はCallback URLs — Twitter Developersに書いてあるんですが、変更後は

みたいです。
また、次のような場合には注意してください。

Callback URLにクエリ文字列を使用したい場合

例えばCallback URLに『https://yourdomain.com?source=twitter』と設定したい場合は、次のようにします。

  1. developer.twitter.com/en/appsのCallback URL設定に『https://yourdomain.com』と登録
  2. POST oauth/request_tokenのcallback_url(oauth_callback)パラメータを『https://yourdomain.com?source=twitter』と指定

Callback URLにlocalhostを使用したい場合

developer.twitter.com/en/appsのCallback URL設定はホスト名が『localhost』だと登録できません。
代わりに、次のいずれかの方法で登録します。

いずれの方法でもポート番号を指定することができるようです(例: http://127.0.0.1:2000)

Callback URLにモバイルアプリへのリンクを設定したい場合

例えばCallback URLに『example://authorize』と設定したい場合は、次のようにします。

  1. developer.twitter.com/en/appsのCallback URL設定に『example://』と登録
  2. POST oauth/request_tokenのcallback_url(oauth_callback)パラメータを『example://authorize』と指定

Twitter Kitを使用している場合

Twitter Kitを使用している場合、冒頭のエラーまたは以下のエラーが発生する場合があります。

Failed to get request token

その場合、developer.twitter.com/en/appsのCallback URL設定を以下のように登録します。

twittersdk://

twitterkit-{アプリのCONSUMERKEY}://

Callback URL設定数が上限に達した場合

developer.twitter.com/en/appsで登録できるCallback URLの数には10個という上限があります。
その上限に達した場合は、Callback URLを単一のアドレスにまとめてPOST oauth/request_tokenでクエリ文字列を使用してください、とのことですたぶん。
自信が無いので引用しておきます。

Need more than 10 callback URLs?
There is a hard limit of 10 callback URLs in the Twitter apps dashboard. Please make sure to combine your callback URLs into a single address and use query strings in your oauth/request_token request.

Callback URLs — Twitter Developers

宣伝

AndroidTwitterアプリを公開中です。
自動更新(疑似User Streams)やマルチアカウント等の機能に対応しています。
よければお試しください。

無料版
play.google.com

有料版
play.google.com

[Twitter4J] Twitter APIのJSONを扱う

java

// JSONを保存するよう設定する
ConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
configurationBuilder.setJSONStoreEnabled(true);
TwitterFactory twitterFactory = new TwitterFactory(configurationBuilder.build());
Twitter twitter = twitterFactory.getInstance();

// 例としてGET statuses/show/:idを行っています
Status status = twitter.showStatus(997324372867076096L);

// 保存されているJSONを取得
String statusJSON = TwitterObjectFactory.getRawJSON(status);

// こうすることでJSONからオブジェクトを生成することもできます
Status status1 = TwitterObjectFactory.createStatus(statusJSON);


上記コードではJSONを保存する設定をConfigurationBuilderクラスから行っていますが、
下記のようにtwitter4j.propertiesファイルから行うこともできます。

twitter4j.properties

jsonStoreEnabled=true

java

// 例としてGET followers/listを行っています
PagableResponseList<User> followersList = TwitterFactory.getSingleton().getFollowersList("mnoqlo", -1);

// 保存されているJSONを取得
String userJSON = TwitterObjectFactory.getRawJSON(followersList.get(0));

// JSONからオブジェクトを生成
User user = TwitterObjectFactory.createUser(userJSON);

jsonStoreEnabledはメモリを食うためデフォルトでfalseになっているとのことなので、
JSONが必要な時に動的に設定できる前者のやり方がいいかもしれません(JSONを取得したいことが多い場合などは別)。

宣伝

AndroidTwitterアプリを公開中です。
自動更新(疑似User Streams)やマルチアカウント等の機能に対応しています。
よければお試しください。

無料版
play.google.com

有料版
play.google.com

[Android] PreferenceFragmentで設定画面を作る

非推奨

PreferenceFragmentはAPI level 28で非推奨になりました。
代わりにPreferenceFragmentCompatを使ってください。
PreferenceFragmentCompatについてはこちらで↓
mnoqlo.hatenablog.com




設定項目をタップするとページ(Fragment)を切り替える設定画面(?)を作ってみます。

完成図

f:id:mnoqlo:20171028064808p:plain

foo設定をクリックすると
f:id:mnoqlo:20171028064815p:plain

コード

SettingsActivity.java

public class SettingsActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_settings);

        // Toolbarにタイトルを設定
        ((Toolbar) findViewById(R.id.toolbar)).setTitle("設定");

        // fragment_container(FrameLayout)部分にMainPreferenceFragmentを挿入
        getFragmentManager().beginTransaction().replace(R.id.fragment_container, MainPreferenceFragment.newInstance()).commit();
    }

}


activity_settings.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!-- themeは各自のテーマを -->
    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:theme="@style/ToolbarTheme" />

    <FrameLayout
        android:id="@+id/fragment_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@+id/toolbar" />

</RelativeLayout>


MainPreferenceFragment.java

public class MainPreferenceFragment extends PreferenceFragment implements Preference.OnPreferenceClickListener {

    public static MainPreferenceFragment newInstance() {
        return new MainPreferenceFragment();
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.preference_main);

        // findPreferenceでkeyに対応するPreferenceを取得し、それがクリックされた時のリスナーを登録する
        // リスナーはこのクラス自体にimplementsしてるのでthis
        findPreference("preference_foo").setOnPreferenceClickListener(this);
        findPreference("preference_bar").setOnPreferenceClickListener(this);
    }


    // リスナー部分
    @Override
    public boolean onPreferenceClick(Preference preference) {
        // keyを見てクリックされたPreferenceを特定
        switch (preference.getKey()) {
            case "preference_foo":
                transitionFragment(FooPreferenceFragment.newInstance());
                break;
            case "preference_bar":
                transitionFragment(BarPreferenceFragment.newInstance());
                break;
        }
        // おそらくですが、クリックした時に反応するリスナーが複数ある場合、ここをtrueにするとこれより後のリスナーが反応しなくなります
        return false;
    }

    private void transitionFragment(PreferenceFragment nextPreferenceFragment) {
        // replaceによるFragmentの切り替えと、addToBackStackで戻るボタンを押した時に前のFragmentに戻るようにする
        getFragmentManager()
                .beginTransaction()
                .addToBackStack(null)
                .replace(R.id.fragment_container, nextPreferenceFragment)
                .commit();
    }

}


Preferenceのxmlファイルは一般的にres/xml以下に作成するみたいですたぶん
preference_main.xml

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
    xmlns:android="http://schemas.android.com/apk/res/android">

    <PreferenceCategory
        android:title="設定">

        <PreferenceScreen
            android:title="foo設定"
            android:key="preference_foo"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

        <PreferenceScreen
            android:title="bar設定"
            android:key="preference_bar"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

    </PreferenceCategory>

</PreferenceScreen>


FooPreferenceFragment.java

public class FooPreferenceFragment extends PreferenceFragment {

    public static FooPreferenceFragment newInstance() {
        return new FooPreferenceFragment();
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.preference_foo);
    }

}


preference_foo.xml

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
    xmlns:android="http://schemas.android.com/apk/res/android">

    <PreferenceCategory
        android:title="foo設定">

        <PreferenceScreen
            android:title="foo"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

    </PreferenceCategory>

</PreferenceScreen>


以下barはfooと名前が変わっただけです
BarPreferenceFragment.java

public class BarPreferenceFragment extends PreferenceFragment {

    public static BarPreferenceFragment newInstance() {
        return new BarPreferenceFragment();
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.preference_bar);
    }

}


preference_bar.xml

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
    xmlns:android="http://schemas.android.com/apk/res/android">

    <PreferenceCategory
        android:title="bar設定">

        <PreferenceScreen
            android:title="bar"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

    </PreferenceCategory>

</PreferenceScreen>

今回はPreferenceScreenをクリックした時のFragmentページ遷移のみです。
より具体的な設定項目の作り方に関しては、それぞれのPreference名(「ListPreference」や「EditTextPreference」等)で検索してみてください。
もし要望があればそちらも書きます。
そりでわ皆さん、良きAndroidライフを~~~

宣伝

AndroidTwitterアプリを公開中です。
自動更新(疑似User Streams)やマルチアカウント等の機能に対応しています。
よければお試しください。

無料版
play.google.com

有料版
play.google.com