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

AndroidーiOS開発比較〜iOSエンジニアから見たAndroidのアレコレ〜

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.

 AndroidーiOS開発比較〜iOSエンジニアから見たAndroidのアレコレ〜

Developers.IO 2016 in Nagoyaでの発表資料です。

Avatar for Takaaki Tanaka

Takaaki Tanaka

April 25, 2016
Tweet

More Decks by Takaaki Tanaka

Other Decks in Programming

Transcript

  1. ରԠ04όʔδϣϯʹ͍ͭͯ w J04 w 9DPEFͷόʔδϣϯΞοϓରԠʹ͸஫ҙ w 9DPEFͷόʔδϣϯʹΑͬͯαϙʔτ͞ΕΔ4XJGUͷόʔ δϣϯ͕ҧ͏ w 9DPEF4XJGU

    w 9DPEF4XJGU w 9DPEF4XJGU w 9DPEF4XJGU w 9DPEF4XJGU w 9DPEF4XJGU  ⡥$MBTTNFUIPE *OD
  2. ରԠ04όʔδϣϯʹ͍ͭͯ w "OESPJE w ରԠ04͸ଟ͍ w 8FC7JFXରԠʹ஫ҙ w #-&Ҋ݅ʹ஫ҙ w

    J04 w 4XJGUͷόʔδϣϯʹ஫ҙ w "54ରԠ  ⡥$MBTTNFUIPE *OD
  3. ࣮૷ํ਑ʹ͍ͭͯ w ։ൃ؀ڥɺ࣮૷ํ਑ʹ͍ͭͯ͸ॳظஈ֊Ͱܾఆ͓ͯ͠ ͘ w ܾఆͨ͠಺༰͸υΩϡϝϯτͱͯ͠࢒͓ͯ͘͠ w ։ൃ؀ڥˠ(JU)VCͷ3&"%.&ʹهࡌ w ࣮૷ํ਑ˠ8JLJʹهࡌ

    w ৽ͨͳνʔϜϝϯόʔ͕ՃΘͬͨࡍʹҰཡͰ֬ೝͰ͖ ΔυΩϡϝϯτΛ੔උ͓ͯ͘͠ʢ8JLJ౳Λ׆༻ʣ w "1*࢓༷΍ཁ݅ఆٛɺઃܭͷࢿྉ͕ҰཡͰ֬ೝͰ͖ΔΑ͏ʹ͠ ͓ͯ͘  ⡥$MBTTNFUIPE *OD
  4. 

  5. 1VTI௨஌Λ࣮૷ͯ͠ΈΔ w 1VTIαʔϏεͷొ࿥ w ($.ʢ(PPHMF$MPVE.FTTBHJOHʣ w "1/4ʢ"QQMF1VTI/PUJpDBUJPO4FSWJDFʣ w 1VTI௨஌ͷ࡞੒ w

    1VTIϝοηʔδΛ࡞੒ w 1VTI௨஌ͷड৴ w 04ຖʹड৴ॲཧΛߦ͏  ⡥$MBTTNFUIPE *OD
  6. "OESPJEଆͷ࡞ۀ  ⡥$MBTTNFUIPE *OD w ($.΁ͷొ࿥ w ϥΠϒϥϦͷΠϯϙʔτ w ύʔϛογϣϯͷઃఆ

    w 1VTIड৴ॲཧͷ࣮૷ w "NB[PO$PHOJUP*%ͷऔಘ w "NB[PO4/4΁τʔΫϯͷૹ৴ w ड৴࣌ͷॲཧͷ࣮૷
  7. ։ൃ؀ڥ w "OESPJE w "OESPJE4UVEJP w +BWB w J04 w

    9DPEF w $PDPB1PETPS$BSUIBHF w 4XJGU  ⡥$MBTTNFUIPE *OD
  8. "OESPJEଆͷ࡞ۀ  ⡥$MBTTNFUIPE *OD w ($.΁ͷొ࿥ w ϥΠϒϥϦͷΠϯϙʔτ w ઃఆϑΝΠϧͷΠϯϙʔτ

    w ύʔϛογϣϯͷઃఆ w 1VTIड৴ॲཧͷ࣮૷ w "NB[PO$PHOJUP*%ͷऔಘ w "NB[PO4/4΁τʔΫϯͷૹ৴ w ड৴࣌ͷॲཧͷ࣮૷
  9. ϥΠϒϥϦͷΠϯϙʔτ  ⡥$MBTTNFUIPE *OD …
 
 android {
 …
 }


    
 dependencies {
 … 
 compile 'com.amazonaws:aws-android-sdk-cognito:2.+'
 compile 'com.amazonaws:aws-android-sdk-sns:2.+'
 
 } w CVJMEHSBEMFΛฤू w "84ͷ4%,Λࢦఆ͢Δ
  10. ϥΠϒϥϦͷΠϯϙʔτ  ⡥$MBTTNFUIPE *OD apply plugin: 'com.google.gms.google-services'
 
 android {


    …
 }
 
 dependencies {
 …
 
 compile "com.google.android.gms:play-services:8.3.0"
 
 …
 } w CVJMEHSBEMFΛฤू w ($.༻ͷϥΠϒϥϦΛద༻͢Δ
  11. ύʔϛογϣϯͷઃఆ  ⡥$MBTTNFUIPE *OD <?xml version="1.0" encoding="utf-8"?>
 <manifest
 package="jp.co.kongmings.android.app"
 xmlns:android="http://schemas.android.com/apk/res/android">


    
 <uses-permission android:name="android.permission.WAKE_LOCK" />
 <uses-permission android:name="android.permission.INTERNET"/>
 
 <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
 <uses-permission android:name="com.google.android.c2dm.permission.REGISTER" />
 
 </manifest> w "OESPJE.BOJGFTUYNMΛฤू w ύʔϛογϣϯͷઃఆ
  12. 1VTIड৴ॲཧͷ࣮૷  ⡥$MBTTNFUIPE *OD <application
 …
 <receiver
 android:name="com.google.android.gms.gcm.GcmReceiver"
 android:exported="true"
 android:permission="com.google.android.c2dm.permission.SEND"

    >
 <intent-filter>
 <action android:name="com.google.android.c2dm.intent.RECEIVE" />
 <category android:name="jp.co.kongmings.android.app" />
 </intent-filter>
 </receiver>
 
 <service
 android:name=".infra.service.MsgGcmListenerService"
 android:exported="false" >
 <intent-filter>
 <action android:name="com.google.android.c2dm.intent.RECEIVE" />
 </intent-filter>
 </service>
 <service
 android:name=".infra.service.RegistrationIntentService"
 android:exported="false" />
 <service android:name=".infra.service.MsgInstanceIDListenerService" android:exported="false">
 <intent-filter>
 <action android:name="com.google.android.gms.iid.InstanceID"/>
 </intent-filter>
 </service>
 </application> w "OESPJE.BOJGFTUYNMΛฤू
  13. 1VTIड৴ॲཧͷ࣮૷  ⡥$MBTTNFUIPE *OD public class MsgGcmListenerService extends GcmListenerService {


    
 static final String TAG = MsgGcmListenerService.class.getSimpleName();
 
 @Override
 public void onMessageReceived(String from, Bundle data) {
 String message = data.getString("message");
 sendNotification(message);
 sendBroadcast(message);
 }
 
 void sendNotification(String message) {
 Intent intent = new Intent(this, MainActivity.class);
 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
 PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent,
 PendingIntent.FLAG_ONE_SHOT);
 
 Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
 NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
 .setSmallIcon(R.mipmap.ic_launcher)
 .setContentTitle("Message received!")
 .setContentText(message)
 .setAutoCancel(true)
 .setSound(defaultSoundUri)
 .setContentIntent(pendingIntent);
 
 NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
 manager.notify(0, notificationBuilder.build());
 }
 
 void sendBroadcast(String message) {
 Intent broadcastIntent = new Intent();
 broadcastIntent.putExtra("message", message);
 broadcastIntent.setAction("MESSAGE_RECEIVED");
 getBaseContext().sendBroadcast(broadcastIntent);
 }
 
 } w ($.͔Βϝοηʔδ͕ฦ͖ͬͯͨ࣌ͷॲཧ
  14. 1VTIड৴ॲཧͷ࣮૷  ⡥$MBTTNFUIPE *OD …
 
 void sendNotification(String message) {


    Intent intent = new Intent(this, MainActivity.class);
 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
 PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent,
 PendingIntent.FLAG_ONE_SHOT);
 
 Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
 NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
 .setSmallIcon(R.mipmap.ic_launcher)
 .setContentTitle("Message received!")
 .setContentText(message)
 .setAutoCancel(true)
 .setSound(defaultSoundUri)
 .setContentIntent(pendingIntent);
 
 NotificationManager manager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
 manager.notify(0, notificationBuilder.build());
 }
 
 ... w ௨஌ηϯλʔʹදࣔͤ͞Δ
  15. 1VTIड৴ॲཧͷ࣮૷  ⡥$MBTTNFUIPE *OD public class MsgGcmListenerService extends GcmListenerService {


    
 …
 
 void sendBroadcast(String message) {
 Intent broadcastIntent = new Intent();
 broadcastIntent.putExtra("message", message);
 broadcastIntent.setAction("MESSAGE_RECEIVED");
 getBaseContext().sendBroadcast(broadcastIntent);
 }
 
 } w ϝοηʔδΛड৴ͨ͜͠ͱΛ௨஌͢Δ
  16. 1VTIड৴ॲཧͷ࣮૷  ⡥$MBTTNFUIPE *OD public class RegistrationIntentService extends IntentService {


    
 public RegistrationIntentService() {
 super("RegistrationIntentService");
 }
 
 @Override
 protected void onHandleIntent(Intent intent) {
 if (intent != null) {
 try {
 InstanceID instanceID = InstanceID.getInstance(this);
 String token = instanceID.getToken(
 getString(R.string.gcm_defaultSenderId),
 GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
 Prefs.put("token", token);
 } catch (IOException e) {
 e.printStackTrace();
 }
 }
 }
 
 } w τʔΫϯऔಘॲཧʹͯτʔΫϯΛอ͓࣋ͯ͘͠
  17. "NB[PO$PHOJUP*%ͷऔಘ  ⡥$MBTTNFUIPE *OD void getCognitoId() {
 new Thread(new Runnable()

    {
 @Override
 public void run() {
 CognitoCachingCredentialsProvider provider = ɹɹɹɹɹɹɹɹɹnew CognitoCachingCredentialsProvider(
 self,
 COGNITO_IDENTITY_POOL_ID,
 AWS_REGION
 );
 final String identityId = provider.getIdentityId();
 Prefs.put("cognito_id", identityId);
 }
 }).start();
 } w $PHOJUP$BDIJOH$SFEFOUJBMT1SPWJEFSʹ $PHOJUP*EFOUJUZ1PPM*%Λࢦఆ͢Δ
  18. "NB[PO4/4΁τʔΫϯͷૹ৴  ⡥$MBTTNFUIPE *OD void sendToken() {
 AmazonSNSClient snsClient =

    new AmazonSNSClient(mProvider);
 snsClient.setRegion(Region.getRegion(AWS_REGION));
 CreatePlatformEndpointRequest createRequest = new CreatePlatformEndpointRequest();
 createRequest.setPlatformApplicationArn(AWS_SNS_APPLICATION_ARN);
 String token = Prefs.get("token");
 createRequest.setToken(token);
 CreatePlatformEndpointResult platformEndpoint = snsClient.createPlatformEndpoint(createRequest);
 String endpointArn = platformEndpoint.getEndpointArn();
 snsClient.subscribe(AWS_SNS_SUBSCRIBE_TOPIC_ARN, "application", endpointArn);
 } w ࢦఆͨ͠5PQJDΛ4VTDSJCF͢Δ
  19. ड৴࣌ͷॲཧͷ࣮૷  ⡥$MBTTNFUIPE *OD private MessageBroadcastReceiver mReceiver;
 
 public class

    MessageBroadcastReceiver extends BroadcastReceiver {
 @Override
 public void onReceive(Context context, Intent intent) {
 Bundle bundle = intent.getExtras();
 String message = bundle.getString("message");
 Toast.makeText(context, message, Toast.LENGTH_LONG).show();
 }
 }
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 …
 
 mReceiver = new MessageBroadcastReceiver();
 IntentFilter intentFilter = new IntentFilter();
 intentFilter.addAction("MESSAGE_RECEIVED");
 registerReceiver(mReceiver, intentFilter);
 }
  20. ϥΠϒϥϦͷΠϯϙʔτ  ⡥$MBTTNFUIPE *OD platform :ios, '8.0' use_frameworks! target 'App'

    do pod 'AWSSNS' end w $PDPB1PETܦ༝ͰΠϯϙʔτ͢Δ w 1PEpMFΛฤू
  21. "NB[PO$PHOJUP*%ͷऔಘ  ⡥$MBTTNFUIPE *OD func application( application: UIApplication, didFinishLaunchingWithOptions launchOptions:

    [NSObject: AnyObject]?) -> Bool { let credentialsProvider = AWSCognitoCredentialsProvider( regionType: AWSRegionType.APNortheast1, identityPoolId: CognitoIdentityPoolId) let defaultServiceConfiguration = AWSServiceConfiguration( region: AWSRegionType.APNortheast1, credentialsProvider: credentialsProvider) AWSServiceManager.defaultServiceManager().defaultServiceConfiguration = defaultServiceConfiguration self.registerForRemoteNotifications() return true } w "844FSWJDF.BOBHFSͷઃఆΛ࣮ࢪ w $PHOJUP*EFOUJUZ1PPM*E͸"84Ͱ࡞੒ͨ͠΋ͷΛࢦఆ͢Δ
  22. "NB[PO4/4΁τʔΫϯͷૹ৴  ⡥$MBTTNFUIPE *OD func application( application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken:

    NSData) { let deviceTokenString = "\(deviceToken)" .stringByTrimmingCharactersInSet(NSCharacterSet(charactersInString:"<>")) .stringByReplacingOccurrencesOfString(" ", withString: "") … } w τʔΫϯऔಘ࣌ʹݺ͹ΕΔϝιου͔ΒτʔΫϯΛऔ ಘ͢Δ
  23. "NB[PO4/4΁τʔΫϯͷૹ৴  ⡥$MBTTNFUIPE *OD … let sns = AWSSNS.defaultSNS() let

    request = AWSSNSCreatePlatformEndpointInput() request.token = deviceTokenString request.platformApplicationArn = AWSSNSApplicationArn sns.createPlatformEndpoint(request).continueWithExecutor( AWSExecutor.mainThreadExecutor(), withBlock: { (task: AWSTask!) -> AnyObject! in if task.error != nil { print("Error: \(task.error)") } else { let createEndpointResponse = task.result as! AWSSNSCreateEndpointResponse let subscribeRequest = AWSSNSSubscribeInput() subscribeRequest.topicArn = self.AWSSNSSubscribeTopicArn subscribeRequest.endpoint = createEndpointResponse.endpointArn subscribeRequest.protocols = "Application" sns.subscribe(subscribeRequest) } return nil }) } w ࢦఆͨ͠5PQJDΛ4VTDSJCF͢Δ
  24. ड৴࣌ͷॲཧ  ⡥$MBTTNFUIPE *OD func application( application: UIApplication, didReceiveRemoteNotification userInfo:

    [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) { if application.applicationState == .Active { if let aps = userInfo["aps"] { if let alert = aps["alert"] { let alertController = UIAlertController( title: nil, message: alert, preferredStyle: .Alert) alertController.addAction( UIAlertAction( title: "OK", style: .Default, handler: nil)) self.window?.rootViewController?.presentViewController( alertController, animated: true, completion: nil) } } } } w 1VTIΛड৴ͨ࣌͠ͷॲཧΛهࡌ͢Δ