Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Support LibraryのDownloadable FontsやEmojiCompatに...

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
Avatar for takahirom takahirom
February 09, 2018
2.7k

Support LibraryのDownloadable FontsやEmojiCompatに対応したアプリを作ろう

DroidKaigi 登壇資料

Avatar for takahirom

takahirom

February 09, 2018
Tweet

More Decks by takahirom

Transcript

  1. ˖ UBLBIJSPN !OFX@SVOOBCMF  ˖ 劤せכ嬁「䃨峔 ׭׿ׄױ׋ַמ׹  ˖ "OESPJEָ㥨ֹ

    ˖ "CFNB57ך"OESPJE،فٔ׾⡲׏גְתׅկ ˖ %SPJE,BJHJⰕ䒭،فٔךٔ٦ت٦׾׃ת׃׋
 ⟃♳ךفؙٕٔؒأز֮׶ָהֲ׀ְׂת׃׋!
 ؎ٝأز٦ٕ׃גזַ׏׋׵؎ٝأز٦ٕ׃גֻ׌ְׁ 荈ⴓחאְג
  2. ˖ %PXOMPBEBCMF'POU ˖ %PXOMPBEBCMF'POUך稱➜ ˖ 'POU3FTPVSDFך稱➜ ˖ %PXOMPBEBCMF'POU׾⢪׏ג׫״ֲ ˖ %PXOMPBEBCMF'POUך➬穈׫

    ˖ וֲװ׏ג%PXOMPBEBCMF'POU׾⢪׏גְַֻ ˖ &NPKJ$PNQBU ˖ &NPKJ$PNQBUך稱➜ ˖ &NPKJ$PNQBUך➬穈׫ ˖ וֲװ׏ג&NPKJ$PNQBU׾⢪׏גְַֻ ˖ ذأز倯岀 ˖ תה׭ 湡如
  3. ˖ فؚٗٓئַا٦أַ׵《䖤ׅ׷ ˖ (PPHMF1MBZ4FSWJDFTח'POU1SPWJEFSָ֮׶
 ׉ַֿ׵《䖤ׅ׷ ˖ ،فٔחؿؓٝز׾㙵׭鴥תזְ ˖ ،فٔחؿؓٝز׾湫䱸تؐٝٗ٦س׃זְ ˖

    (PPHMF1MBZ4FSWJDFTָؿؓٝز׾
 ٍؗحءُ׃גְֶגֻ׸׷ IUUQTEFWFMPQFSBOESPJEDPNHVJEFUPQJDTVJMPPL BOEGFFMEPXOMPBEBCMFGPOUTIUNM״׶ %PXOMPBEBCMF'POUהכ
  4. ˖ ؕأةيؿؓٝز׾黝䘔דֹ׷ ˖ وذٔ،ٕرؠ؎ٝך黝䘔 ˖ 畭劣㔿剣ךؿؓٝز׾⢪׻זֻ⳿勻׷ ˖ "1,؟؎ؤ׾幾׵ׇ׷ ˖ ׉׸ח״׶،فٔך؎ٝأز٦ٕ䧭⸆桦ָ㟓װׇ׷

    ˖ 'POU׾➭ך،فٔהءؑ،דֹ׷ ˖ 鸐⥋ꆀך⵴幾 ˖ ًٌٔך⢪欽ꆀך⵴幾 ˖ ر؍أؙأل٦أך⵴幾 %PXOMPBEBCMF'POUךًٔحز
  5. 'POU3FTPVSDF #VOEMFE'POUGPOUGBNJMZ YNM  <?xml version="1.0" encoding="utf-8"?> <font-family xmlns:app=“../apk/res-auto”> <font

    app:font="@font/orbitron_regular" app:fontStyle="normal" /> <font app:font="@font/orbitron_bold" app:fontStyle="normal" app:fontWeight="700" /> </font-family> UFYU4UZMFח״׏ג⢪ֲؿؓٝز׾㢌ִ׷ <TextView android:fontFamily="@font/orbitron" android:textStyle="bold"
  6. "QQ$PNQBU5FYU7JFXַ׵ 《䖤׃חְֻ switch (name) { case "TextView": view = new

    AppCompatTextView(context, attrs); break; case "ImageView": view = new AppCompatImageView(context, attrs); break; "QQ$PNQBU7JFX*OBUFSKBWB ٖ؎،ؐزךˑ5FYU7JFX˒ך ➿׻׶ח"QQ$PNQBU5FYU7JFXָ ⡲׵׸׷
  7. ResourcesCompat.FontCallback replyCallback = new ResourcesCompat.FontCallback() { @Override public void onFontRetrieved(@NonNull

    Typeface typeface) onAsyncTypefaceReceived(textViewWeak, typeface); } @Override public void onFontRetrievalFailed(int reason) { // Do nothing. } }; try { // Note the callback will be triggered on the UI thread. mFontTypeface = a.getFont(fontFamilyId, mStyle, replyCallback); // If this call gave us an immediate result, ignore any "QQ$PNQBU5FYU)FMQFS $BMM#BDL׾⡲䧭
  8. @Override public void onFontRetrievalFailed(int reason) { // Do nothing. }

    }; try { // Note the callback will be triggered on the UI thread mFontTypeface = a.getFont(fontFamilyId, mStyle, replyCallback); // If this call gave us an immediate result, ignore any pending callbacks. mAsyncFontPending = mFontTypeface == null; } catch (UnsupportedOperationException | Resources.NotFoundException e) { // Expected if it is not a font resource. } private void onAsyncTypefaceReceived(WeakReference<TextView textViewWeak, Typeface typeface) { if (mAsyncFontPending) { mFontTypeface = typeface; final TextView textView = textViewWeak.get(); 5JOU5ZQFE"SSBZHFU'POU ד《䖤ׅ׷
  9. private void onAsyncTypefaceReceived(WeakReference<TextView> textViewWeak, Typeface typeface) { if (mAsyncFontPending) {

    mFontTypeface = typeface; final TextView textView = textViewWeak.get(); if (textView != null) { textView.setTypeface(typeface, mStyle); } } } ꬊず劍דⳢ椚׃ג《䖤דֹ׋׵ UFYU7JFXTFU5ZQFGBDF ד إحزׅ׷
  10. 1BDLBHF.BOBHFS׾⢪׏ג ػح؛٦آך縭せثؑحؙ List<byte[]> signatures; PackageInfo packageInfo = packageManager.getPackageInfo(info.packageName, PackageManager.GET_SIGNATURES); signatures

    = convertToByteArrayList(packageInfo.signatures); … List<List<byte[]>> requestCertificatesList = request.getCertificates(); for (int i = 0; i < requestCertificatesList.size(); ++i) { ػح؛٦آوط٦آַٍ׵ (PPHMF1MBZ4FSWJDFTך،فٔך ءؚطثٍ׾《䖤׃גغ؎ز⴨חׅ׷ ˑDPNHPPHMFBOESPJEHNT (PPHMF1MBZ4FSWJDFT 'POUT$POUSBDU$PNQBU
  11. List<List<byte[]>> requestCertificatesList = request.getCertificates(); for (int i = 0; i

    < requestCertificatesList.size(); ++i) { List<byte[]> requestSignatures = new ArrayList<>(requestCertificatesList.get(i)); … if (equalsByteArrayList(signatures, requestSignatures)) { return info; } } return null; غ؎ز⴨׾嫰鯰׃ג♧筰ז׵䞔㜠׾鵤ׅ
  12. val uri = Uri.Builder() .scheme(ContentResolver.SCHEME_CONTENT) .authority("com.google.android.gms.fonts") .build() var cursor =

    contentResolver.query( uri, arrayOf( FontsContractCompat.Columns._ID, FontsContractCompat.Columns.FILE_ID, FontsContractCompat.Columns.TTC_INDEX, … ), "query = ?", arrayOf("Days One"), null ) $POUFOU3FTPMWFS׾⢪׏ג《䖤ׅ׷ 'POUせ
  13. ➬穈׫ך鍑铡 'POUT$POUSBDU$PNQBU ⯓玎ך$POUFOU1SPWJEFSך倯岀חכ縭せثؑحָؙⰅ׏גֶ ׵׆ծ㸜Ⰻדכזְדׅկ 'POUT$POUSBDU׾⢪ֲהػح؛٦آךثؑحؙ׮׃ג㸜Ⰻח 䭯׏גֿ׸תׅկ val request = FontRequest(

    "com.google.android.gms.fonts", "com.google.android.gms", "Days One", R.array.com_google_…_fonts_certs_prod ) FontsContractCompat.requestFont( this, request, object : FontsContractCompat.FontRequestCallback() {
  14. val request = FontRequest( "com.google.android.gms.fonts", "com.google.android.gms", "Days One", R.array.com_google_…_fonts_certs_prod )

    FontsContractCompat.requestFont( this, request, object : FontsContractCompat.FontRequestCallback() override fun onTypefaceRetrieved(typeface: Type textView.typeface = typeface } override fun onTypefaceRequestFailed(reason: In super.onTypefaceRequestFailed(reason) } }, Handler() 'POU3FRVFTU׾⡲䧭 $POUFOU3FTPMWFSח䗳銲ז"VUIPSJUZせװ ؿؓٝزせծ縭せָⰅ׏גְ׷ٔا٦أ׾ 䭷㹀ׅ׷
  15. quest = FontRequest( m.google.android.gms.fonts", m.google.android.gms", ys One", rray.com_google_…_fonts_certs_prod ontractCompat.requestFont( this,

    request, object : FontsContractCompat.FontRequestCallback() { override fun onTypefaceRetrieved(typeface: Typeface?) { textView.typeface = typeface } override fun onTypefaceRequestFailed(reason: Int) { super.onTypefaceRequestFailed(reason) } }, Handler() 《׏גֿ׸׋؝٦ٕغحؙד 5FYU7JFXךUZQFGBDFחإحزׅ׷
  16. 3FTPVSDF$PNQBU׾⢪׏ג 'POU3FTPVSDF׾《׶⳿ׅ 'POUT$POUSBDU$PNQBUכ$POUFOU1SPWJEFS״׶嚂דָׅծ
 (PPHMF1MBZ4FSWJDFTךػح؛٦آせ䭷㹀׃׋׶הַ㣐㢌דׅ ⯓玎铡僇׃גְ׋'POU3FTPVSDF׾⢪׏ג׫ת׃׳ֲ 'POU3FTPVSDFד⯓玎剅ְגְ׋ػح؛٦آせזוָ鎸鯹ׁ׸גְ תׅ <?xml version="1.0" encoding="utf-8"?>

    <font-family xmlns:app="http://schemas.android.com/apk/res-auto" app:fontProviderAuthority="com.google.android.gms.fonts" app:fontProviderPackage="com.google.android.gms" app:fontProviderQuery="Days One" app:fontProviderCerts="@array/com_google_android_gms_fonts_certs"> </font-family>
  17. 3FTPVSDFT$PNQBU ResourcesCompat.getFont( this, R.font.orbitron, object : ResourcesCompat.FontCallback() { override fun

    onFontRetrieved(typeface: Typeface) { fontText.typeface = typeface } override fun onFontRetrievalFailed(reason: Int) { } }, Handler()) ꬊず劍ד《䖤׮דֹתׅկ 4VQQPSU-JCַ׵鷄⸇ׁ׸׋ًاحس
  18. %PXOMPBEBCMF'POUח 傈劤铂ָזְ⟝ Get Started with the Google Fonts for Android

    ͱ͍͏ϖʔδʹҎԼͷΑ͏ʹ͋Γ·͢ fonts.google.comʹ͋ΔϑΥϯτ͕࢖͑Δʂ
  19. 'POU3FTPVSDF椚䟝涸ז㼪Ⰵ <style name=“TextAppearance.App.Title" parent="TextAppearance.AppCompat.Title"> <item name="android:textSize">21sp</item> <item name="android:fontFamily">@font/notosans_medium</item> </style> <style

    name="TextAppearance.App.Subhead" parent="TextAppearance.AppCompat.Subhead"> <item name="android:textSize">17sp</item> <item name="android:fontFamily">@font/notosans_regular</item> </style> ׉׸׊׸ך5FYU"QQFBSBODF欽䠐׃גGPOU'BNJMZה㣐ֹׁ׾䭷㹀 ֿֿדGPOUOPUPTBOT@NFEJVNPUGזוד ؿؓٝزؿ؋؎ٕ،فٔחⰅ׸׷ %SPJE,BJHJ״׶
  20. رؿٕؓزךؿؓٝزך鏣㹀 ذ٦وהַדז׿הַדֹזְַ <style name=“AppTheme" parent="Theme.AppCompat.Light"> <item name=“android:textAppearance">@style/TextAppearance.hogehoge</item> <item name=“android:textAppearanceSmall”>@style/TextAppearance..</item> <item

    name="android:textAppearanceButton">@style/TextAppearance…</item> <item name=“android:textAppearanceMediumInverse”>@style/TextAppearance…</i ɻɻɻɻ ❌דֹ׷ֽו׋ֻׁ׿֮׷կ㣐㢌
  21. رؿٕؓزךؿؓٝزך鏣㹀 DISJTKFOY$BMMJHSBQIZ׾⢪ֲ $BMMJHSBQIZהכ"OESPJEךأةٝت٦سזٓ؎ـٓٔד رؿٕؓزךؿؓٝز׾鏣㹀דֹ׷׮ך @Override public void onCreate() { super.onCreate();

    CalligraphyConfig.initDefault(new CalligraphyConfig.Builder() .setDefaultFontPath("fonts/Roboto-RobotoRegular.ttf") .setFontAttrId(R.attr.fontPath) .build() ); ❌׋׌׃$BMMJHSBQIZכ僓ַ׵֮׷ٓ؎ـٓٔד 倜׃ְ'POU3FTPVSDFכ䭷㹀דֹ׆ծ✼䳔䚍׮זְ
  22. &NPKJ$PNQBUך㛇劤涸ז⢪ְ倯 val fontRequest = FontRequest( "com.google.android.gms.fonts", "com.google.android.gms", "Noto Color EmojiCompat",

    R.array.com_google_android_gms_fonts_certs) val config = FontRequestEmojiCompatConfig(context, fontRequest) EmojiCompat.init(config) "QQMJDBUJPOPO$SFBUF
  23. &NPKJ$PNQBUך㛇劤涸ז⢪ְ倯 val fontRequest = FontRequest( "com.google.android.gms.fonts", "com.google.android.gms", "Noto Color EmojiCompat",

    R.array.com_google_android_gms_fonts_certs) val config = FontRequestEmojiCompatConfig(context, fontRequest) EmojiCompat.init(config) ⯓玎ך'POU3FRVFTU׾⢪׏ג &NPKJ$PNQBUJOJU דⴱ劍⻉ "QQMJDBUJPOPO$SFBUF
  24. &NPKJ$PNQBUך㛇劤涸ז⢪ְ倯 val fontRequest = FontRequest( "com.google.android.gms.fonts", "com.google.android.gms", "Noto Color EmojiCompat",

    R.array.com_google_android_gms_fonts_certs) val config = FontRequestEmojiCompatConfig(context, fontRequest) EmojiCompat.init(config) ⯓玎ך'POU3FRVFTU׾⢪׏ג &NPKJ$PNQBUJOJU דⴱ劍⻉ "QQMJDBUJPOPO$SFBUF implementation “com.android.support:support-emoji:27.0.2"
  25. ➬穈׫חⰅ׷⵸ח窩俑㶵חאְג // String -> code point val face = "\ud83d\udc68"

    val codePoint: Int = Character.toCodePoint(face[0], face[1]) println(Integer.toHexString(codePoint)) // code point -> String val charArray: CharArray = Character.toChars(codePoint) val string = String(charArray) println(string) ؝٦سه؎ٝز׾《䖤׃׋׶ծ 俑㶵⴨ח湫ֿׅהָדֹ׷ $IBSBDUFSUP$PEF1PJOUחDIBS׾א床ׅ׌ֽ
  26. ➬穈׫חⰅ׷⵸ח窩俑㶵חאְג // String -> code point val face = "\ud83d\udc68"

    val codePoint: Int = Character.toCodePoint(face[0], face[1]) println(Integer.toHexString(codePoint)) // code point -> String val charArray: CharArray = Character.toChars(codePoint) val string = String(charArray) println(string) $IBSBDUFSUP$IBST ח؝٦سه؎ٝز床ׅ׌ֽ
  27. ➬穈׫חⰅ׷⵸ח窩俑㶵חאְג val face = Character.toChars(0x1f468) val lightSkin = Character.toChars(0x1f3fb) val

    zwj = Character.toChars(0x200d) val computer = Character.toChars(0x1f4bb) val programmer = face + lightSkin + zwj + computer programmer.forEach { println(Integer.toHexString(it.toInt())) } 6 '6 ''#6 %6 '## ;8+ ֿך؝٦سه؎ٝز׾؝٦سד邌植ׅ׷חכ ֿ׸דת׆כDIBSךBSSBZָ《䖤דֹ׋ 如ךأٓ؎سד˒QSPHSBNNFS˒׾⢪ֲ
  28. ➬穈׫חⰅ׷⵸ח窩俑㶵חאְג textView.typeface = ResourcesCompat.getFont(this, R.font.noto_color_emoji) textView.text = String(programmer) // or

    textView.text = "\ud83d\udc68\ud83c\udffb\u200d\ud83d\udcbb" &NPKJ$PNQBUָזֻג׮窩俑㶵כ ⹛ָֻկկ
  29. public final class TypefaceEmojiSpan extends EmojiSpan { … @Override public

    void draw(@NonNull final Canvas canvas, …, @NonNull final Paint paint) { getMetadata().draw(canvas, x, y, paint); } … } QBJOUחTFU5ZQFGBDF׃ג DBOWTESBX5FYU ׅ׷׌ֽ &NPKJ.FUBEBUBKBWB public void draw(@NonNull final Canvas canvas, final float x,… @NonNull final Paint paint) { final Typeface typeface = mMetadataRepo.getTypeface(); … paint.setTypeface(typeface); … canvas.drawText(…, paint); }
  30. 窩俑㶵׾ⴻ㹀ׅ׷➬穈׫ ֿך加׾⢪׏גծ俑㶵⴨ַ׵א׆א؝٦سه؎ٝز׾ 铣׿דծ加ח֮׷EBUB׾黝䘔׃גְֻ int currentOffset = start; int codePoint =

    Character.codePointAt(charSequence, currentOffset); while (currentOffset < end && addedCount < maxEmojiCount) { final int action = sm.check(codePoint); switch (action) { case ACTION_ADVANCE_BOTH: start += Character.charCount(Character.codePointAt(charSequence, start)); currentOffset = start; if (currentOffset < end) { codePoint = Character.codePointAt(charSequence, currentOffset); } …
  31. ذأز倯岀 ˖ 㛇劤涸ח縧ֹ䳔׻׏גְ׷ַוֲַד然钠ָדֹ ׷ ˖ ؿؓٝزך麩ְכ然钠ׅ׷ךָ㔭ꨇזךדծ NVSPPLBHPEJJNBHFזוד然钠ׅ׷ה葺ַ׏ ׋ ˖ ֲתֻ⹛ַזְהֹכ4VQQPSU-JCSBSZזךדծ兛

    鸐חرغحؚד鋅׸׷׃؝٦س׮铣׭׷ ˖ 4VQQPSU-JCSBSZך刿倜㾶娖׾׫גְ׋׌ֽ׷הغ ؚؿ؍حؙأ׾걼籕ח׃גְ׷״ֲזךדծ岣鋔 ׃׋קֲָ葺ׁ׉ֲ
  32. ⿫罋俑柃 䒷欽 ˖ "OESPJE%FWFMPQFSTIUUQTEFWFMPQFSBOESPJEDPNJOEFYIUNM ˖ "OESPJE0QFO4PVSDF1SPKFDUIUUQTTPVSDFBOESPJEDPN ˖ &NPKJ$IBSUTIUUQVOJDPEFPSHFNPKJDIBSUTGVMMFNPKJMJTUIUNM ˖ &YQMPSJOHUIF"OESPJE&NPKJ$PNQBU-JCSBSZIUUQTNFEJVNDPNFYQMPSJOHBOESPJE

    FYQMPSJOHUIFBOESPJEFNPKJDPNQBUJCJMJUZMJCSBSZCGCCBB ˖ (PPHMF*0IUUQTXXXZPVUVCFDPNXBUDI W/,WF+'6 ˖ QPUBUPUJQTד"OESPJEך'POUワ׶ך倜堣腉חאְג涪邌׃ת׃׋կIUUQT RJJUBDPNUTVZPTIJUFNTCFED ˖ +BWBח״׷6OJDPEF؟ٗ؜٦زفؚٗٓىؚٝIUUQTXXXJCNDPN EFWFMPQFSXPSLTKQZTMMJCSBSZKBWBKVOJDPEF@TVSSPHBUFJOEFYIUNM ˖ "OESPJEָד窩俑㶵ח׍ׯ׿ה㼎䘔׃׋IUUQTNTUTTLCMPHTQPUKQ FNPKJIUNM