Androidの本当にあった怖い話

24
Copyright(c) Yusuke Yamamoto All rights reserved. Androidの怖い話 2011/1/17 山本 裕介 @yusukey 本当にあった

description

 

Transcript of Androidの本当にあった怖い話

Page 1: Androidの本当にあった怖い話

Copyright(c) Yusuke Yamamoto All rights reserved.

Androidの怖い話2011/1/17

山本 裕介 @yusukey

本当にあった

Page 2: Androidの本当にあった怖い話

Copyright(c) Yusuke Yamamoto All rights reserved.

山本 裕介http://samuraism.jp/@yusukey

http://tinyurl.com/android-java

Page 3: Androidの本当にあった怖い話

Copyright(c) Yusuke Yamamoto All rights reserved.

↑を開発していますJava用Twitter APIライブラリ

サポートプラットフォーム• JDK1.4.2~•Google App Engine

•Android

Page 4: Androidの本当にあった怖い話

Copyright(c) Yusuke Yamamoto All rights reserved.

AndroidとJavaの非互換性について話します

Page 5: Androidの本当にあった怖い話

Copyright(c) Yusuke Yamamoto All rights reserved.

Androidで使えないパッケージの怖い話

Page 6: Androidの本当にあった怖い話

Copyright(c) Yusuke Yamamoto All rights reserved.

発生した問題

02-20 18:03:59.843: WARN/dalvikvm(526): VFY: unable to resolve new-instance 105 (Lsun/misc/BASE64Encoder;) in Ltwitter4j/http/HttpClient; 02-20 18:03:59.843: WARN/dalvikvm(526): VFY: rejecting opcode 0x22 at 0x0011

怖い話その1:Androidではsun.misc.* / com.sun.* が使えない

new sun.misc.BASE64Encoder().encode(buf);

Page 7: Androidの本当にあった怖い話

Copyright(c) Yusuke Yamamoto All rights reserved.

施した対策• BASE64のエンコーダーを自前で用意

(Commons-Codec利用でもok)

• sun.misc.* だけでなく com.sun.* 等も使えないので注意

Page 8: Androidの本当にあった怖い話

Copyright(c) Yusuke Yamamoto All rights reserved.

XMLの怖い話

Page 9: Androidの本当にあった怖い話

Copyright(c) Yusuke Yamamoto All rights reserved.

XML

// XML をテキスト形式に変換private String toString(Element doc){ StringWriter output = new StringWriter(); Transformer t = TransformerFactory.newInstance()

.newTransformer(); t.transform(new DOMSource(doc),

new StreamResult(output)); return output.toString();}

• Twitter4Jにあったデバッグ用のコード

Page 10: Androidの本当にあった怖い話

Copyright(c) Yusuke Yamamoto All rights reserved.

発生した問題

07-07 23:55:42.993: ERROR/dalvikvm(11182): Could not find method javax.xml.transform.TransformerFactory.newInstance, referenced from method twitter4j.TwitterResponse.toString

怖い話その2:AndroidにはXSLTが内蔵されていない

Page 11: Androidの本当にあった怖い話

Copyright(c) Yusuke Yamamoto All rights reserved.

施した対策// XML をテキスト形式に変換private static String toString(Element doc){ StringWriter output = new StringWriter(); try{ Transformer t = TransformerFactory.newInstance().newTransformer(); t.transform(new DOMSource(doc),

new StreamResult(output)); return output.toString(); }catch(ClassNotFoundException cnfe){ // javax.xml.transform.TransformerFactory がなければ // “”を返す return “”; }}

Page 12: Androidの本当にあった怖い話

Copyright(c) Yusuke Yamamoto All rights reserved.

発生した問題01-16 23:20:58.637: ERROR/AndroidRuntime(209): Uncaught handler: thread main exiting due to uncaught exception01-16 23:20:58.668: ERROR/AndroidRuntime(209): java.lang.VerifyError: com.example.MyActivity at java.lang.Class.newInstanceImpl(Native Method) at java.lang.Class.newInstance(Class.java:1472) at android.app.Instrumentation.newActivity(Instrumentation.java:1097) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2316) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2417) at android.app.ActivityThread.access$2100(ActivityThread.java:116) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1794) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:123) at android.app.ActivityThread.main(ActivityThread.java:4203) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:521) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:791) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:549) at dalvik.system.NativeStart.main(Native Method)

怖い話その3:クラスが見つからないとVerifyErrorが発生

Page 13: Androidの本当にあった怖い話

Copyright(c) Yusuke Yamamoto All rights reserved.

施した対策-- // XML をテキスト形式に変換-- private static String toString(Element doc){-- StringWriter output = new StringWriter();-- try{-- Transformer t = TransformerFactory.newInstance().newTransformer();-- t.transform(new DOMSource(doc),-- new StreamResult(output));-- return output.toString();-- }catch(ClassNotFoundException cnfe){-- // javax.xml.transform.TransformerFactory がなければ-- // “”を返す-- return “”;-- }--}

Transformerを使わない・・・

Page 14: Androidの本当にあった怖い話

Copyright(c) Yusuke Yamamoto All rights reserved.

XMLの日本語問題String xml = "<title>English &amp; 日本語</title>";DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();dbf.setCoalescing(true);dbf.setExpandEntityReferences(true);ByteArrayInputStream stream = new ByteArrayInputStream( xml.getBytes());DocumentBuilder builder = null;builder = dbf.newDocumentBuilder();Document doc = builder.parse(stream);

Node titleNode = doc.getFirstChild();NodeList children = titleNode.getChildNodes();System.out.println(children.item(0).getTextContent());

Page 15: Androidの本当にあった怖い話

Copyright(c) Yusuke Yamamoto All rights reserved.

発生した問題String xml = "<title>English &amp; 日本語</title>";DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();dbf.setCoalescing(true);dbf.setExpandEntityReferences(true);ByteArrayInputStream stream = new ByteArrayInputStream( xml.getBytes());DocumentBuilder builder = null;builder = dbf.newDocumentBuilder();Document doc = builder.parse(stream);

Node titleNode = doc.getFirstChild();NodeList children = titleNode.getChildNodes();System.out.println(children.item(0).getTextContent());

怖い話その4:XMLパーサが使い物にならない

期待値: “English & 日本語”

実際: “English”

Page 16: Androidの本当にあった怖い話

Copyright(c) Yusuke Yamamoto All rights reserved.

施した対策

XMLを使わない・・・

Page 17: Androidの本当にあった怖い話

Copyright(c) Yusuke Yamamoto All rights reserved.

• Twitterはxml, JSON, atom, rssをサポート

• JSON

• JavaScript Object Notation

• Web APIで標準となりつつあるフォーマット

Twitter4JをJSONへ移行

Page 18: Androidの本当にあった怖い話

Copyright(c) Yusuke Yamamoto All rights reserved.

JSONの怖い話

Page 19: Androidの本当にあった怖い話

Copyright(c) Yusuke Yamamoto All rights reserved.

JSONの例

JSONObject json = new JSONObject

("{\"foo\":null,\"longvalue\":\"13857270119014401\"}");

// true を期待

System.out.println(json.isNull("foo"));

// true を期待

System.out.println(null == json.getString("foo"));

// false を期待

System.out.println("null".equals(json.getString("foo")));

// 13857270119014401 を期待

System.out.println(json.getLong("longvalue"));

(“foo”:null, “longvalue”:”13857270119014401”}

Page 20: Androidの本当にあった怖い話

Copyright(c) Yusuke Yamamoto All rights reserved.

JSONObject json = new JSONObject

("{\"foo\":null,\"longvalue\":\"13857270119014401\"}");

// true を期待

System.out.println(json.isNull("foo"));

// true を期待

System.out.println(null == json.getString("foo"));

// false を期待

System.out.println("null".equals(json.getString("foo")));

// 13857270119014401 を期待

System.out.println(json.getLong("longvalue"));

発生した問題

true

true

true

13857270119014400

怖い話その5:jsonのライブラリが古すぎてバグバグ

Page 21: Androidの本当にあった怖い話

Copyright(c) Yusuke Yamamoto All rights reserved.

施した対策

json.orgの最新ライブラリをパッケージを変えて使用twitter4j.internal.org.json.*

Page 22: Androidの本当にあった怖い話

Copyright(c) Yusuke Yamamoto All rights reserved.

怖い話のまとめ• XSLTは使えない(Froyoで修正済み)

• クラスが見つからない場合にVerifyError• Eclair(Android 2.1)で修正済み

• XMLの日本語、外部エンティティ解決問題

• Froyo(Android 2.2)で修正

• JSONライブラリのバグ

• 修正されない・・・• Sunのパッケージは使えない

Page 23: Androidの本当にあった怖い話

Copyright(c) Yusuke Yamamoto All rights reserved.

public static final boolean IS_DALVIK;

static{

try {

// dalvik.system.VMRuntime class should be existing on

Android platform.

// @see http://developer.android.com/reference/dalvik/

system/VMRuntime.html

Class.forName("dalvik.system.VMRuntime");

dalvikDetected = true;

} catch (ClassNotFoundException cnfe) {

dalvikDetected = false";

}

IS_DALVIK = dalvikDetected;

}

オマケ• Android環境の検出

Page 24: Androidの本当にあった怖い話

Copyright(c) Yusuke Yamamoto All rights reserved.

- Issue 2607 - android - org.apache.harmony.xml.parsers.DocumentBuilderImpl does not resolve unicode entity refshttp://code.google.com/p/android/issues/detail?id=2607

- Issue 9244 - android - org.json packages out of datehttp://code.google.com/p/android/issues/detail?id=9244

- Issue 13830 - JSONObject.getString() returns "null" string literal for null value instead of null object.http://code.google.com/p/android/issues/detail?id=13830

- Issue 13831 - JSONObject.getLong() returns rounded and inaccurate valuehttp://code.google.com/p/android/issues/detail?id=13831

関連リンク