こんにちは。きんくまです。
もうやっている人もいないと思うので、個人的なメモです。その2
Androidです。Intentで他のアプリに、Uriを連携したいです。
以前は以下のようなことができていました。
File file = new File("path"); Uri myuri = Uri.fromFile(file);
それで、バージョンがあがってセキュリティが厳しくなって、この方法だと他のアプリに連携できなくなっていました。
調べたところ、FileProviderというのを使うといいみたい。
FileProvider | Android Developers
file:// 形式じゃなくて、 content:// 形式で送ります。詳しい実装方法は他にゆずります。
それで、これを使ったANEを作りたかったのだけど、すごくハマってしまい時間がかかってしまいました。
大いなる参考サイト
DigitalStrawberry/ANE-Share: Adobe AIR native extension for sharing text and bitmap content.
このソースをみつつやっていたのですが、細かいところでAndroid Studioのバージョンが上がっていたりして、うまくいきませんでした。
FileProviderの入っているsuppport-v4のjarを取り出す
FileProviderは android.support.v4 という外部パッケージに入っています。
なので、こいつを何とかしないといけない。
普通にgradleにこういう風に書いてもだめだった。上の参考のANEはうまくいっているので、何か関係しているのかもしれない。
設定をimplementationじゃなくてAPIにするとか、、。
dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' androidTestImplementation 'com.android.support.test:runner:1.0.2' implementation 'com.android.support:support-v4:27.1.1' }
で、結局最後のsuppor-v4の行は消しました。
Android SDKの以下のパス
Android/sdk/extras/android/m2repository/com/android/support
ここにほしいやつがあります。この中から以下のものを取り出しました。
support-compat-25.3.1.aar support-core-ui-25.3.1.aar support-core-utils-25.3.1.aar support-fragment-25.3.1.aar support-media-compat-25.3.1.aar support-v4-25.3.1.aar
どこにリストがあるかというとここです。
v4 Support Libraries
どうやらsuppor-v4は、あるバージョンから、ライブラリの機能が複数のファイルに分割されたみたいです。
で、aarというのはライブラリの形式です。こいつをzipに拡張子をかえて、解凍します。
すると、中に classes.jarというのを含んだフォルダができあがりますので、classes.jarをそれぞれのファイル名に書き換えて取り出します。
support-compat-25.3.1.jar support-core-ui-25.3.1.jar support-core-utils-25.3.1.jar support-fragment-25.3.1.jar support-media-compat-25.3.1.jar support-v4-25.3.1.jar
これらをAnrdoidライブラリプロジェクトのlibsフォルダに追加します。FlashRuntimeExtensions.jarと同じところ。
それで、ネイティブのコードを書いていきます。
今回、メールに複数添付ファイルをするANEを作ったので、こんな感じです。
package com.kumade.ane.mailanelibandroid; import java.io.File; import java.util.ArrayList; import android.content.Context; import android.content.Intent; import android.net.Uri; import android.support.v4.content.FileProvider; import android.util.Log; import com.adobe.fre.FREArray; import com.adobe.fre.FREContext; import com.adobe.fre.FREFunction; import com.adobe.fre.FREObject; public class SendMailFunction implements FREFunction { public final String TAG = "com.kumade.mail"; public String[] toRecipients; public String[] ccRecipients; public String[] bccRecipients; public String subject; public String bodyText; public String[] attachementPaths; @Override public FREObject call(FREContext context, FREObject[] args) { readArguments(args); sendMail(context); return null; } public void readArguments(FREObject[] args){ FREArray argFREArray = null; //to try { Log.d(TAG, "to:"); argFREArray = (FREArray)args[0]; //arrayLength = getFREArrayLength(argFREArray); //toRecipients = new String[arrayLength]; toRecipients = storeStringsFromFREArray(argFREArray); //storeToRecipients((FREArray)arg1[0]); }catch(Exception e){ e.printStackTrace(); } //cc try { Log.d(TAG, "cc:"); argFREArray = (FREArray)args[1]; //arrayLength = getFREArrayLength(argFREArray); //ccRecipients = new String[arrayLength]; ccRecipients = storeStringsFromFREArray(argFREArray); //storeCcRecipients((FREArray)arg1[1]); }catch(Exception e){ e.printStackTrace(); } //bcc try { Log.d(TAG, "bcc:"); argFREArray = (FREArray)args[2]; //arrayLength = getFREArrayLength(argFREArray); //bccRecipients = new String[arrayLength]; bccRecipients = storeStringsFromFREArray(argFREArray); //storeBccRecipients((FREArray)arg1[2]); }catch(Exception e){ e.printStackTrace(); } //subject try{ subject = args[3].getAsString(); Log.d(TAG, "subject: \n" + subject); }catch(Exception e){ e.printStackTrace(); } //body text try{ bodyText = args[4].getAsString(); Log.d(TAG, "bodyText: \n" + bodyText); }catch(Exception e){ e.printStackTrace(); } //attachment paths try { Log.d(TAG, "attachment paths:"); argFREArray = (FREArray)args[5]; attachementPaths = storeStringsFromFREArray(argFREArray); }catch(Exception e){ e.printStackTrace(); } } public void sendMail(FREContext context){ final Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND_MULTIPLE); emailIntent.setType("text/plain"); emailIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); ArrayList<Uri> attachmentUris = new ArrayList<Uri>(); for (String file : attachementPaths) { File fileIn = new File(file); Context appContext = context.getActivity().getApplicationContext(); Uri myURI = FileProvider.getUriForFile(appContext, appContext.getPackageName() + ".fileprovider", fileIn); attachmentUris.add(myURI); } emailIntent.putExtra(Intent.EXTRA_EMAIL, toRecipients); if(ccRecipients.length > 0){ emailIntent.putExtra(Intent.EXTRA_CC, ccRecipients); } if(bccRecipients.length > 0){ emailIntent.putExtra(Intent.EXTRA_BCC, bccRecipients); } emailIntent.putExtra(Intent.EXTRA_SUBJECT, subject); emailIntent.putExtra(Intent.EXTRA_TEXT, bodyText); if(attachmentUris.size() > 0){ emailIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, attachmentUris); } context.getActivity().startActivity(Intent.createChooser(emailIntent, "Email:")); } public int getFREArrayLength(FREArray freArray) throws Exception{ return (int)(freArray.getLength()); } public String[] storeStringsFromFREArray(FREArray freArray) throws Exception{ String[] targetStrings = new String[(int)freArray.getLength()]; for(int i = 0; i < targetStrings.length; i++){ FREObject fObj = freArray.getObjectAt(i); targetStrings[i] = fObj.getAsString(); Log.d(TAG, "string" + i + " " + targetStrings[i]); } return targetStrings; } }
あと、res/xml の中に以下のようなファイルを追加します。この辺は、さきほどのAndroid SDK公式リファレンスを参照。
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-path name="external_docs" path="."/> </paths>
Android Studioでのビルドは、以前書いた記事を参考にGradleで clean > build します。
[AS3] Android Studio でもANE用のjarを作りたい
そうすると、ANEを作るための jar はここにあります。
AndroidStudioプロジェクト/モジュール名/build/outputs/aar/モジュール名-release.aar
aarなんですが、さきほどと同じように、aar を zip に変えて解凍して出てくるclasses.jarファイルを取り出します。
ANEを作る準備ができたので、これからANEをビルドします。
android内のフォルダはこんな感じになります。androidMailANE.jarというのは、さきほどの モジュール名-release.aar からとりだしてファイル名を変えた.jarファイル。
res/xml/ のところは階層になるようにそれぞれフォルダ作ってください。
androidMailANE.jar library.swf res/xml/filepaths.xml support-compat-25.3.1.jar support-core-ui-25.3.1.jar support-core-utils-25.3.1.jar support-fragment-25.3.1.jar support-media-compat-25.3.1.jar support-v4-25.3.1.jar
それで、android_options.xmlというのを作ります。
<platform xmlns="http://ns.adobe.com/air/extension/32.0"> <packagedDependencies> <packagedDependency>support-compat-25.3.1.jar</packagedDependency> <packagedDependency>support-core-ui-25.3.1.jar</packagedDependency> <packagedDependency>support-core-utils-25.3.1.jar</packagedDependency> <packagedDependency>support-fragment-25.3.1.jar</packagedDependency> <packagedDependency>support-media-compat-25.3.1.jar</packagedDependency> <packagedDependency>support-v4-25.3.1.jar</packagedDependency> </packagedDependencies> <packagedResources> <packagedResource> <packageName>com.kumade.ane.mailanelibandroid</packageName> <folderName>res</folderName> </packagedResource> </packagedResources> </platform>
ようやくANEのビルドです。ここで、Android-ARM の -platformoptions をつけ忘れて、数日苦しんだのはナイショです、、。
#adt command ======== adt -package \ -target ane ${ANEName} extension.xml \ -platform iPhone-ARM \ -platformoptions ios_options.xml \ -C ${iOSDir} . \ -swc ${ASLibSwcName} \ -platform Android-ARM \ -platformoptions android_options.xml \ -C android . \ -platform default \ -C default .
これで、ANEのビルドができました。
使うとき
普通にANEを追加するところまではいいのですが、application.xmlに以下の部分を追加する必要があります。
<android> <manifestAdditions><![CDATA[ <manifest android:installLocation="auto"> <!--このあたりのパーミッションは適当。WRITE_EXTERNAL_STORAGEだけ必要かも --> <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <application> <provider android:name="android.support.v4.content.FileProvider" android:authorities="air.あなたのアプリID.fileprovider" android:grantUriPermissions="true" android:exported="false"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/filepaths" /> </provider> </application> </manifest> ]]></manifestAdditions> </android>
android:authorities=”air.あなたのアプリID.fileprovider”
となっています。AndroidSDKの説明ページではここのところが “アプリID.fileprovider” となっているのですが、AIR for Androidは applicaiton.xml で指定したIDに “air” という接頭詞を自動でつけるので注意が必要です。
あと注意するのは、AS3の方で、ファイルの書き込み権限が必要か見て、必要そうならアラートを出してあげることぐらいでしょうか。
private function requestFilePermissionOnAndroidIfNeeds():Boolean{ // DeviceInfoは自作のユーティリティクラスなので気にしないでくださいまし if(DeviceInfo.sharedInfo.isAndroid){ var myFile:File = File.applicationDirectory; if(File.permissionStatus == PermissionStatus.GRANTED){ return true; }else{ try { myFile.requestPermission(); }catch(e:Error){ trace("Permission Error"); } return false; } }else{ return true; } }
同じようなところで苦しむ人が、日本にあと2人くらいはいるんじゃないかと思って書いてみました。
ロストテクノロジーのつらみですなーw
■ 自作iPhoneアプリ 好評発売中!
・フォルメモ - シンプルなフォルダつきメモ帳
・ジッピー電卓 - 消費税や割引もサクサク計算!
■ LINEスタンプ作りました!
毎日使える。とぼけたウサギ