Facebook Android SDKで認証してPostする際のポイント
DroidNPをFacebookに対応させました。
その際のハマりポイントをメモしておきます。
要は、Facebook Android SDKで認証してPostする際のポイントです。
かなり雑な内容ですが。。。
■Facebook Android SDKのDLとimport
https://github.com/facebook/facebook-android-sdk
からDL。
"facebook"ディレクトリをeclipseでimport。
自分のプロジェクトを右クリック。
properties > Android > Library > Add...
にてimportしたプロジェクト(デフォルトだと"com_facebook_android")を選択。OKを押す。
■認証で使用したメソッド
--
com.facebook.android.Facebook.authorize(
Activity activity,
String[] permissions,
int activityCode,
DialogListener listener)
--
* activity
Contextをキャストしても良いっぽい。
(XxxActivity)getContext()みたいな感じ。
* permissions
"offline_access"と"publish_stream"を指定。
offline_accessは認証tokenの期限切れを防ぐ為。
publish_streamはウォールへの書き込み権限。
* activityCode
startActivityForResultに渡すrequestCodeのようなもの。後述。
* listener
後述。
■認証後の処理
(A) Facebook公式アプリが端末にインストールされている場合
onActivityResultに戻るので、前述のactivityCode == requestCodeの時に専用の処理を書く。
--Java(onActivityResultにて)--
switch (requestCode) {
case REQUEST_CODE_FACEBOOK_OAUTH:
String token = data.getExtras().getString(Facebook.TOKEN);
// TODO: tokenの保存等。
break;
default:
break;
}
--
(B) Facebook公式アプリが端末にインストールされていない場合
--Java(Facebook.DialogListener)--
@Override
public void onFacebookError(FacebookError e) {
// TODO:
}
@Override
public void onError(DialogError e) {
// TODO:
}
@Override
public void onComplete(Bundle values) {
String token = values.getString(Facebook.TOKEN);
// TODO: tokenの保存等。
}
@Override
public void onCancel() {
// TODO:
}
--
■認証サンプルソース
--Java--
Facebook facebook = new Facebook("[Facebookで登録したアプリのID]");
facebook.authorize(
(XxxActivity)getContext(),
new String[] {"offline_access","publish_stream"},
1,
new Facebook.DialogListener() {
@Override
public void onFacebookError(FacebookError e) {
// TODO:
}
@Override
public void onError(DialogError e) {
// TODO:
}
@Override
public void onComplete(Bundle values) {
String token = values.getString(Facebook.TOKEN);
// TODO: tokenの保存等。onActivityResultも忘れずに。(この場合、requestCodeは1。)
}
@Override
public void onCancel() {
// TODO:
}
});
--
■認証後のサンプル
--Java--
private void setFacebookSettings(String token){
Facebook facebook = new Facebook("[Facebookで登録したアプリのID]");
facebook.setAccessToken(token);
try {
String response = facebook.request("me");
JSONObject json;
try {
json = new JSONObject(response);
String name = json.get("name").toString();
String id = json.get("id").toString();
// TODO: nameやidをSharedPreferencesに保存する。等。
} catch (JSONException e) {
// TODO:
}
} catch (MalformedURLException e) {
// TODO:
} catch (IOException e) {
// TODO:
}
}
--
■その他
Facebook側の話。
Android Marketでの公開を前提としている場合、開発用のkey hash登録と併せて
Android Market用のAPK作成時に使用するkeystoreでのkey hash作成/登録も忘れずに。
エミュレータにマーケットアプリ等を入れる。
エミュにマーケットアプリ等を入れたかったので調べました。
先に、参考にさせて頂いたURLです。
参考1:
Android SDKを使おう
http://androidsdk.web.fc2.com/
参考2:(必要なファイルはここからDLさせて頂きました。)
WindowsでAndroid SDKを使おう
http://androidsdk.zouri.jp/
以下、上記”参考1”の手順の自分メモです。
一通り済ませた後、マーケットアプリを起動してGoogleのアカウントを求められるところまで確認しました。
(1)
eclipse等からエミュを作る。
(2)
(Win XPだと) Documents and Settings/[ユーザ名]/.android/avd/[作ったエミュ名].avd/
に、エミュと同一OSバージョンの
android-sdk-windows/platforms/android-[OSバージョン値]/images/system.img
をコピー。
(3)
コマンドプロンプトから
android-sdk-windows/tools
に移動。
emulator -avd A22 -partition-size 100
と打つ。
(4)
コマンドプロンプトをもう一つ起動。
android-sdk-windows/platform-tools
に移動。
(5)
adb -s emulator-5554 shell
エミュレータのルート・シェル(Linuxのコマンドプロンプト)を起動。
mount -o remount,rw -t yaffs2 /dev/block/mtdblock0 /system
システムフォルダを読み取り専用から読み書き可能に属性を変更。
chmod 777 /system/app
システム・アプリのフォルダに書き込みを許可。
exit
エミュレータのルート・シェル(Linuxのコマンドプロンプト)を終了。
adb -s emulator-5554 push Vending.apk /system/app/
マーケット本体のインストール。
adb -s emulator-5554 push GoogleServicesFramework.apk /system/app/
必要なファイルをインストール。
adb -s emulator-5554 push MarketUpdater.apk /system/app/
必要なファイルをインストール。
adb -s emulator-5554 push Development.apk /system/app/
必要なファイルをインストール。
adb shell rm /system/app/SdkSetup.apk
不要なファイルを削除。
* Vending.apk
* GoogleServicesFramework.apk
* MarketUpdater.apk
* Development.apk
は android-sdk-windows/platform-tools に有ることとする。
(6)
2つのコマンドプロンプトを閉じて、エミュレータをすべて止める。
(Win XPだと) Documents and Settings/[ユーザ名]/.android/avd/[作ったエミュ名].avd/
の
userdata-qemu.img
と
cache.img
を削除。
(7)
eclipseからエミュレータを起動。
備考:
一通りの手順を終えた段階で
Documents and Settings/[ユーザ名]/.android/avd/[作ったエミュ名].avd/system.img
を別の場所にコピー、保存しておけば再構築が楽??
Android開発環境構築メモ 2011/07/09
Androidの開発環境をeclipseからMOTODEV Studio for Androidに移行しようと思います。
これまでAndroid開発は、Android開発に特化したeclipseで行っていました。
それはつまり、MOTODEVのコンセプトに似ているので、移行しようかなと。
(DBそのまま見れたりしないかな。。。)
いつもの通り、ミニマム構成をメモ。
■Android SDK
http://developer.android.com/sdk/index.html
■MOTODEV Studio for Android 2.2.1
http://developer.motorola.com/docstools/motodevstudio/
■plugin
▼archive
* JStyle 3.6.2
http://mergedoc.sourceforge.jp/index.html#jstyle.html
* subclipse 1.6.18
http://subclipse.tigris.org/servlets/ProjectDocumentList?folderID=2240
▼update site
* FindBugs
http://findbugs.cs.umd.edu/eclipse
android開発環境構築メモ 2011/07/02
eclipseを新しくしたのでメモ。
極力、ミニマム構成。
■Android SDK
http://developer.android.com/sdk/index.html
■eclipse
http://www.eclipse.org
■eclipse plugin
▼archive
* JStyle
http://mergedoc.sourceforge.jp/index.html#/pleiades.html
▼update site
* Android SDK用プラグイン
http://dl-ssl.google.com/android/eclipse
▼Eclipse Marketplace
* DBViewer
* Egit
* FindBugs
* subclipse
Androidで各種プレイヤーの再生情報を取得する方法 2
基本的には、以下の方法となります。
* Androidで各種プレイヤーの再生情報を取得する方法
http://mamor-blog.tumblr.com/post/2525335625/android
今回は、Scrobble Droidについて書きます。
* Scrobble Droid - DeveloperAPI
http://code.google.com/p/scrobbledroid/wiki/DeveloperAPI
Scrobble Droidと連携するプレイヤは、以下のActionのIntentをsendBroadcastしています。
"net.jjc1138.android.scrobbler.action.MUSIC_STATUS"
このIntentをBroadcastReceiverで引っ掛ける事が第一です。
この時、前述の方法と同様に
String artist = bundle.getString("artist");
String album = bundle.getString("album");
String track = bundle.getString("track");
で情報を取得出来るケースがあれば、出来ないケースもあります。
出来ない場合、次の方法を試してみてください。
--【Java】--
long id = bundle.getInt("id");
if(id<1) id = bundle.getLong("id");
if(1<=id) {
Cursor c = context.getContentResolver().query(
ContentUris.withAppendedId(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, id),
new String[]{
MediaStore.Audio.Media.ARTIST,
MediaStore.Audio.Media.ALBUM,
MediaStore.Audio.Media.TITLE
},
null,
null,
null
);
if(c.moveToFirst()) {
String artist =
c.getString(c.getColumnIndex(MediaStore.Audio.Media.ARTIST));
String album =
c.getString(c.getColumnIndex(MediaStore.Audio.Media.ALBUM));
String track =
c.getString(c.getColumnIndex(MediaStore.Audio.Media.TITLE));
// TODO:
}
c.close();
}
--
if(1<=id)としている理由ですが、MixZingでこの方法を試した時、
idが0のIntentが必ず(?)2度発生し、その後に、再生している曲のidが発生した為です。
MediaStore.Audio.MediaのDB構成を熟知しているワケではありませんが、
idが0のレコードは、仮に存在していたとしても、特殊なレコードのはずです。
Android + Velocityで、端末の言語設定に対応したローカルWEBを作る。
assetsに静的htmlを置く方法では、端末の言語設定に対応したローカルWEBを作成できません。
そこで、Android + Velocityを試してみました。
ソースは以下に置いてあります。
http://code.google.com/p/madroom-project/source/browse/#svn%2Ftrunk%2FAndroidVelocity
もしかしたら、そのうちプロジェクト名を変更するかもしれないので、上記URLが無効な場合は
http://code.google.com/p/madroom-project/source/browse/
の中を探してみてください。
以下、ポイントです。
上記URLのソースと照らし合わせてみてください。
(ちょこちょこと手直しするかもしれませんが、ポイントはそれほど変わらないと考えています。)
▼Velocityのログ出力をオフにする
Velocity.setProperty(VelocityEngine.RUNTIME_LOG_LOGSYSTEM_CLASS,
"org.apache.velocity.runtime.log.NullLogSystem");
▼html側からAndroidのメソッドをcallする
* Velocityを使用する以上、画面遷移毎にプログラムを通す必要があります。
--【java】--
mWebView.addJavascriptInterface(new JavaScriptCallback(), "android");
--
--【JavaScript】--
function transition(page){
android.transition(page);
}
--
--【java】--
public class JavaScriptCallback {
public void transition(final String page) {
mPage = page;
mHandler.post(new Runnable() {
public void run() {
mWebView.loadData(getDataByVelocity(), MIME_TYPE_TEXT_HTML, ENCODE);
}
});
}
}
--
JavaScriptのandroid.transition(page)はJavaScriptCallbackクラスの
transition(String page)を呼び出します。
このpage値により、Velocityに当てはめる値を制御しています。
この時、strings.xmlの値を渡せば、端末の言語設定に対応可能となります。
尚、WebViewの更新は別スレッドで行わないとエラーが出ました。
P.S.
例えば、HELPやチュートリアルの作成に使えるかもしれません。
パラメータの送信については問題が残る。。。
Androidの公式Gmailアプリが新着メール受信したタイミングをキャッチする。
BroadcastReceiverで可能です。
但し、公式Gmailアプリのバージョン(OSバージョン??)によって若干異なります。
Android2.1系とAndroid2.2系以上とで以下のよう2つのBroadcastReceiverを用意する必要がありました。
(記述方法次第では1つにまとめられるかもしれませんが。)
尚、以下のBroadcastReceiverはInboxへの新着のみをキャッチします。
<!-- act=android.intent.action.PROVIDER_CHANGED dat=content://gmail-ls/unread/^i typ=gmail-ls -->
<receiver android:name=".ProviderChangedReceiver">
<intent-filter>
<action android:name="android.intent.action.PROVIDER_CHANGED" />
<data
android:scheme="content"
android:host="gmail-ls"
android:pathPrefix="/unread/^i"
android:mimeType="*/*"
/>
</intent-filter>
</receiver>
<!-- act=android.intent.action.PROVIDER_CHANGED dat=content://gmail-ls/unread/^i -->
<receiver android:name=".ProviderChangedReceiver2">
<intent-filter>
<action android:name="android.intent.action.PROVIDER_CHANGED" />
<data
android:scheme="content"
android:host="gmail-ls"
android:pathPrefix="/unread/^i"
/>
</intent-filter>
</receiver>
P.S.
公式Gmailアプリのデータ取得などは以下の方法で、今のところ可能です。
http://mamor-blog.tumblr.com/post/5437791221/android-gmail
透過率を含めてActivityの背景色を動的に変更する。
Activityの背景色を、透過率を含めて(argbで)変更する場合、以下の形で可能です。
int a = 0;
int r = 0;
int g = 0;
int b = 0;
PaintDrawable paintDrawable = new PaintDrawable(Color.argb(a,r,g,b));
getWindow().setBackgroundDrawable(paintDrawable);
透過率を表すaは0で完全に透明。255で完全に不透明。となります。
なので、"不透明度"と表現して良いと思います。
尚、"android:windowIsTranslucent=true"等、
透過Activityを使用する為の下準備は、当然、必要となります。
Androidの有料アプリ/無料アプリのソース管理。
有料アプリと無料アプリとで、どのようにしてソースの一元管理をしようか。
といった話です。
まず、以下を参考に、Androidライブラリを試してみました。
http://d.hatena.ne.jp/tomorrowkey/20101020/1287584710
http://rokuta96.blog137.fc2.com/blog-category-5.html
つまり、以下のように3つのプロジェクトを作成します。
処理の分岐はgetPackageName()で行うことを前提にしています。
xxxCore
…ライブラリプロジェクト(すなわち実態)
xxxPay
…有料アプリプロジェクト
xxxFree
…無料アプリプロジェクト
しかし、この方法だと、xxxPayとxxxFreeのmanifest.xmlの
<provider>のandroid:authoritiesが重複してしまいました。
結果、後にインストールしようとした方で
INSTALL_FAILED_CONFLICTING_PROVIDER
のエラーが発生してしまいます。
有料/無料アプリの各マニフェストでandroid:authoritiesの値を変えようにも、
そもそも、その実態はライブラリの中。となると、変えることが出来ません。
(Content Providerを継承したクラスの中でAUTHORITYを定義していたので。)
ですので、考えを改め、より原始的な方法(?)でトライしてみようと思います。
具体的には、以下のパッケージ構成。
xxxPay
net.madroom.xxx.core
…実態
net.madroom.xxx.env
…実態
xxxFree
net.madroom.xxx.core
…xxxPayのnet.madroom.xxx.coreへリンク
net.madroom.xxx.env
…実態
net.madroom.xxx.envの中に環境設定クラスを作成。
このクラスに、Content Providerを継承したクラスの中で定義していたAUTHORITYを記述。
当然、Content Providerを継承したクラスの中にあったAUTHORITYは削除します。
これでおそらく、パッケージ構成は完全に同一なまま、
静的なフィールドの値分けが出来ると思います。
getPackageName()による処理分岐も可能なはず。
あるいは、環境設定クラスに
IS_PAY_VERSION = true/false
といったフラグフィールドを用意してもOKと思います。
帰ったら試してみよう。
コケたら追記します。
P.S.
結局は、環境依存する部分をライブラリに含めるな。
という、当たり前の話だったのかもしれません。
2011/05/16 追記
コケました。とは言っても、R.javaが見つからないよ。エラーです。
ですので、xxxFreeで使用するR.javaも、リンクでxxxPayのR.javaを指すようにして解決。
これで、DBもバラバラでうまく動きました。
ホントはアプリ名をそれぞれで少し変えたかったので
valuesのstring.xmlもローカルで別管理にしたかったのですが。
上記の方法だと、それは無理っぽいです。
なので、string.xmlにapp_nameを有料版用と無料版用でそれぞれ用意。
(app_name_payとapp_name_freeみたいな感じです。)
これを、各AndroidManifest.xmlで使い分ける事にします。
(結果的にですが、この方がはるかに楽ですね。)
これで、有料/無料アプリ毎に編集する必要があるファイルは
* AndroidManifest.xml
* 環境設定クラス
の2ファイルのみとなりました。
とりあえず、めでたし。
Android公式Gmailアプリのデータを取得する。
必要なものは
http://grepcode.com/search/?query=gmail
にある
android.provider.Gmail
です。
伴い、以下も必要になります。
com.google.android.collect.Lists
com.google.android.collect.Maps
com.google.android.collect.Sets
上記URLのandroid.provider.Gmailのソースからリンクで辿れます。
モノが揃ったらjarにでもしておきましょう。
細かい使い方は、ソースを見ましょう。ということになりますが。
最も厄介なのは、Android公式Gmailアプリのソースがそもそも非公開である事だと思いました。