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

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

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

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

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Λड৴ͨ࣌͠ͷॲཧΛهࡌ͢Δ