Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AmazonSNS - AwsCredentials.properties - NullPointerException

I am new to Android Studio and intelliJ.

I am trying to work with AmazonSNS - Push. I am unable to figure out how to add AwsCredentials.properties file to classpath of the module. I get a NPE at line 57 in the image below(at method getResourceAsStream()). I added the required keys in AwsCredentials.properties file.

enter image description here

Error:

enter image description here

In the questions that i have come across on StackOverflow regarding similar issues, some suggested that the file should be in the root folder, where, src is. I placed it in the same folder as that of src, but still getting the NPE. I also tried placing the file in com/test/ but with no use.

How do i solve this? Are there any other steps involved?

EDIT after starting a bounty - Adding java files

Here is what i did till now..

  1. Create an Android Application called MyApplication. Imported all classes(AndroidMobilePushApp.java, ExternalReceiver.java, MessageReceivingService.java) from the demo application. Added required libs, and ran it and got the registationId as response from Amazon.

  2. In the same application, i created a new module called snspush and imported SNSMobilePush.java file into it. Also imported the AwsCredentials.properties file to the same path as that of SNSMobilePush.java. Added the keys in AwsCredentials.properties file.

  3. Followed the steps in documentation to uncomment necessary funtions.

Project Structure:

enter image description here

Java files:

  1. AndroidMobilePushApp.java:

    public class AndroidMobilePushApp extends AppCompatActivity { private TextView tView; private SharedPreferences savedValues; private String numOfMissedMessages;

    // Since this activity is SingleTop, there can only ever be one instance. This variable corresponds to this instance.
    public static Boolean inBackground = true;
    
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        numOfMissedMessages = getString(R.string.num_of_missed_messages);
        setContentView(R.layout.activity_main);
        tView = (TextView) findViewById(R.id.tViewId);
        tView.setMovementMethod(new ScrollingMovementMethod());
        startService(new Intent(this, MessageReceivingService.class));
    }
    
    public void onStop(){
        super.onStop();
        inBackground = true;
    }
    
    public void onRestart(){
        super.onRestart();
        tView.setText("");;
    }
    
    public void onResume(){
        super.onResume();
        inBackground = false;
        savedValues = MessageReceivingService.savedValues;
        int numOfMissedMessages = 0;
        if(savedValues != null){
            numOfMissedMessages = savedValues.getInt(this.numOfMissedMessages, 0);
        }
        String newMessage = getMessage(numOfMissedMessages);
        if(newMessage!=""){
            Log.i("displaying message", newMessage);
            tView.append(newMessage);
        }
    }
    
    public void onNewIntent(Intent intent){
        super.onNewIntent(intent);
        setIntent(intent);
    }
    
    // If messages have been missed, check the backlog. Otherwise check the current intent for a new message.
    private String getMessage(int numOfMissedMessages) {
        String message = "";
        String linesOfMessageCount = getString(R.string.lines_of_message_count);
        if(numOfMissedMessages > 0){
            String plural = numOfMissedMessages > 1 ? "s" : "";
            Log.i("onResume","missed " + numOfMissedMessages + " message" + plural);
            tView.append("You missed " + numOfMissedMessages +" message" + plural + ". Your most recent was:\n");
            for(int i = 0; i < savedValues.getInt(linesOfMessageCount, 0); i++){
                String line = savedValues.getString("MessageLine"+i, "");
                message+= (line + "\n");
            }
            NotificationManager mNotification = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
            mNotification.cancel(R.string.notification_number);
            SharedPreferences.Editor editor=savedValues.edit();
            editor.putInt(this.numOfMissedMessages, 0);
            editor.putInt(linesOfMessageCount, 0);
            editor.commit();
        }
        else{
            Log.i("onResume","no missed messages");
            Intent intent = getIntent();
            if(intent!=null){
                Bundle extras = intent.getExtras();
                if(extras!=null){
                    for(String key: extras.keySet()){
                        message+= key + "=" + extras.getString(key) + "\n";
                    }
                }
            }
        }
        message+="\n";
        return message;
    }
    
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
    
    public boolean onOptionsItemSelected(MenuItem item) {
        if(item.getItemId() == R.id.menu_clear){
            tView.setText("");
            return true;
        }
        else{
            return super.onOptionsItemSelected(item);
        }
    }
    

    }

  2. ExternalReceiver.java

    package com.test.awstestapp;

    import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.os.Bundle;

    public class ExternalReceiver extends BroadcastReceiver {

    public void onReceive(Context context, Intent intent) {
        if(intent!=null){
            Bundle extras = intent.getExtras();
            if(!AndroidMobilePushApp.inBackground){
                MessageReceivingService.sendToApp(extras, context);
            }
            else{
                MessageReceivingService.saveToLog(extras, context);
            }
        }
    }
    

    }

  3. MessageReceivingService.java

public class MessageReceivingService extends Service{ private GoogleCloudMessaging gcm; public static SharedPreferences savedValues;

public static void sendToApp(Bundle extras, Context context){
    Intent newIntent = new Intent();
    newIntent.setClass(context, AndroidMobilePushApp.class);
    newIntent.putExtras(extras);
    newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    context.startActivity(newIntent);
}

public void onCreate(){
    super.onCreate();
    final String preferences = getString(R.string.preferences);
    savedValues = getSharedPreferences(preferences, Context.MODE_PRIVATE);
    // In later versions multi_process is no longer the default
    if(VERSION.SDK_INT >  9){
        savedValues = getSharedPreferences(preferences, Context.MODE_MULTI_PROCESS);
    }
    gcm = GoogleCloudMessaging.getInstance(getBaseContext());
    SharedPreferences savedValues = PreferenceManager.getDefaultSharedPreferences(this);
    if(savedValues.getBoolean(getString(R.string.first_launch), true)){
        register();
        SharedPreferences.Editor editor = savedValues.edit();
        editor.putBoolean(getString(R.string.first_launch), false);
        editor.commit();
    }
    // Let AndroidMobilePushApp know we have just initialized and there may be stored messages
    sendToApp(new Bundle(), this);
}

protected static void saveToLog(Bundle extras, Context context){
    SharedPreferences.Editor editor=savedValues.edit();
    String numOfMissedMessages = context.getString(R.string.num_of_missed_messages);
    int linesOfMessageCount = 0;
    for(String key : extras.keySet()){
        String line = String.format("%s=%s", key, extras.getString(key));
        editor.putString("MessageLine" + linesOfMessageCount, line);
        linesOfMessageCount++;
    }
    editor.putInt(context.getString(R.string.lines_of_message_count), linesOfMessageCount);
    editor.putInt(context.getString(R.string.lines_of_message_count), linesOfMessageCount);
    editor.putInt(numOfMissedMessages, savedValues.getInt(numOfMissedMessages, 0) + 1);
    editor.commit();
    postNotification(new Intent(context, AndroidMobilePushApp.class), context);
}

protected static void postNotification(Intent intentAction, Context context){
    final NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);

    final PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intentAction, Notification.DEFAULT_LIGHTS | Notification.FLAG_AUTO_CANCEL);
    final Notification notification = new NotificationCompat.Builder(context).setSmallIcon(R.mipmap.ic_launcher)
            .setContentTitle("Message Received!")
            .setContentText("")
            .setContentIntent(pendingIntent)
            .setAutoCancel(true)
            .getNotification();

    mNotificationManager.notify(R.string.notification_number, notification);
}

private void register() {
    new AsyncTask(){
        protected Object doInBackground(final Object... params) {
            String token;
            try {
                token = gcm.register(getString(R.string.project_number));
                Log.i("registrationId", token);
            } 
            catch (IOException e) {
                Log.i("Registration Error", e.getMessage());
            }
            return true;
        }
    }.execute(null, null, null);
}

public IBinder onBind(Intent arg0) {
    return null;
}

}

SNSMobilePush.java

package com.test;

public class SNSMobilePush {

    private AmazonSNSClientWrapper snsClientWrapper;

    public SNSMobilePush(AmazonSNS snsClient) {
        this.snsClientWrapper = new AmazonSNSClientWrapper(snsClient);
    }

    public static final Map<Platform, Map<String, MessageAttributeValue>> attributesMap = new HashMap<Platform, Map<String, MessageAttributeValue>>();
    static {
        attributesMap.put(Platform.ADM, null);
        attributesMap.put(Platform.GCM, null);
        attributesMap.put(Platform.APNS, null);
        attributesMap.put(Platform.APNS_SANDBOX, null);
        attributesMap.put(Platform.BAIDU, addBaiduNotificationAttributes());
        attributesMap.put(Platform.WNS, addWNSNotificationAttributes());
        attributesMap.put(Platform.MPNS, addMPNSNotificationAttributes());
    }

    public static void main(String[] args) throws IOException {
        /*
         * TODO: Be sure to fill in your AWS access credentials in the
         * AwsCredentials.properties file before you try to run this sample.
         * http://aws.amazon.com/security-credentials
         */
        AmazonSNS sns = new AmazonSNSClient(new PropertiesCredentials(
                SNSMobilePush.class
                        .getResourceAsStream("AwsCredentials.properties")));

        sns.setEndpoint("https://sns.us-west-2.amazonaws.com");
        System.out.println("===========================================\n");
        System.out.println("Getting Started with Amazon SNS");
        System.out.println("===========================================\n");
        try {
            SNSMobilePush sample = new SNSMobilePush(sns);
            /* TODO: Uncomment the services you wish to use. */
            sample.demoAndroidAppNotification();
            // sample.demoKindleAppNotification();
            // sample.demoAppleAppNotification();
            // sample.demoAppleSandboxAppNotification();
            // sample.demoBaiduAppNotification();
            // sample.demoWNSAppNotification();
            // sample.demoMPNSAppNotification();
        } catch (AmazonServiceException ase) {
            System.out
                    .println("Caught an AmazonServiceException, which means your request made it "
                            + "to Amazon SNS, but was rejected with an error response for some reason.");
            System.out.println("Error Message:    " + ase.getMessage());
            System.out.println("HTTP Status Code: " + ase.getStatusCode());
            System.out.println("AWS Error Code:   " + ase.getErrorCode());
            System.out.println("Error Type:       " + ase.getErrorType());
            System.out.println("Request ID:       " + ase.getRequestId());
        } catch (AmazonClientException ace) {
            System.out
                    .println("Caught an AmazonClientException, which means the client encountered "
                            + "a serious internal problem while trying to communicate with SNS, such as not "
                            + "being able to access the network.");
            System.out.println("Error Message: " + ace.getMessage());
        }
    }

    public void demoAndroidAppNotification() {
        // TODO: Please fill in following values for your application. You can
        // also change the notification payload as per your preferences using
        // the method
        // com.amazonaws.sns.samples.tools.SampleMessageGenerator.getSampleAndroidMessage()
        String serverAPIKey = "REPLACED_WITH_SERVER_API_KEY";
        String applicationName = "snspushtest";
        String registrationId = "REPLACED_WITH_REG_ID_FROM_AMAZON";
        snsClientWrapper.demoNotification(Platform.GCM, "", serverAPIKey,
                registrationId, applicationName, attributesMap);
    }

    public void demoKindleAppNotification() {
        // TODO: Please fill in following values for your application. You can
        // also change the notification payload as per your preferences using
        // the method
        // com.amazonaws.sns.samples.tools.SampleMessageGenerator.getSampleKindleMessage()
        String clientId = "";
        String clientSecret = "";
        String applicationName = "";

        String registrationId = "";
        snsClientWrapper.demoNotification(Platform.ADM, clientId, clientSecret,
                registrationId, applicationName, attributesMap);
    }

    public void demoAppleAppNotification() {
        // TODO: Please fill in following values for your application. You can
        // also change the notification payload as per your preferences using
        // the method
        // com.amazonaws.sns.samples.tools.SampleMessageGenerator.getSampleAppleMessage()
        String certificate = ""; // This should be in pem format with \n at the
                                    // end of each line.
        String privateKey = ""; // This should be in pem format with \n at the
                                // end of each line.
        String applicationName = "";
        String deviceToken = ""; // This is 64 hex characters.
        snsClientWrapper.demoNotification(Platform.APNS, certificate,
                privateKey, deviceToken, applicationName, attributesMap);
    }

    public void demoAppleSandboxAppNotification() {
        // TODO: Please fill in following values for your application. You can
        // also change the notification payload as per your preferences using
        // the method
        // com.amazonaws.sns.samples.tools.SampleMessageGenerator.getSampleAppleMessage()
        String certificate = ""; // This should be in pem format with \n at the
                                    // end of each line.
        String privateKey = ""; // This should be in pem format with \n at the
                                // end of each line.
        String applicationName = "";
        String deviceToken = ""; // This is 64 hex characters.
        snsClientWrapper.demoNotification(Platform.APNS_SANDBOX, certificate,
                privateKey, deviceToken, applicationName, attributesMap);
    }

    public void demoBaiduAppNotification() {
        /*
         * TODO: Please fill in the following values for your application. If
         * you wish to change the properties of your Baidu notification, you can
         * do so by modifying the attribute values in the method
         * addBaiduNotificationAttributes() . You can also change the
         * notification payload as per your preferences using the method
         * com.amazonaws
         * .sns.samples.tools.SampleMessageGenerator.getSampleBaiduMessage()
         */
        String userId = "";
        String channelId = "";
        String apiKey = "";
        String secretKey = "";
        String applicationName = "";
        snsClientWrapper.demoNotification(Platform.BAIDU, apiKey, secretKey,
                channelId + "|" + userId, applicationName, attributesMap);
    }

    public void demoWNSAppNotification() {
        /*
         * TODO: Please fill in the following values for your application. If
         * you wish to change the properties of your WNS notification, you can
         * do so by modifying the attribute values in the method
         * addWNSNotificationAttributes() . You can also change the notification
         * payload as per your preferences using the method
         * com.amazonaws.sns.samples
         * .tools.SampleMessageGenerator.getSampleWNSMessage()
         */
        String notificationChannelURI = "";
        String packageSecurityIdentifier = "";
        String secretKey = "";
        String applicationName = "";
        snsClientWrapper.demoNotification(Platform.WNS,
                packageSecurityIdentifier, secretKey, notificationChannelURI,
                applicationName, attributesMap);
    }

    public void demoMPNSAppNotification() {
        /*
         * TODO: Please fill in the following values for your application. If
         * you wish to change the properties of your MPNS notification, you can
         * do so by modifying the attribute values in the method
         * addMPNSNotificationAttributes() . You can also change the
         * notification payload as per your preferences using the method
         * com.amazonaws
         * .sns.samples.tools.SampleMessageGenerator.getSampleMPNSMessage ()
         */
        String notificationChannelURI = "";
        String applicationName = "";
        snsClientWrapper.demoNotification(Platform.MPNS, "", "",
                notificationChannelURI, applicationName, attributesMap);
    }

    private static Map<String, MessageAttributeValue> addBaiduNotificationAttributes() {
        Map<String, MessageAttributeValue> notificationAttributes = new HashMap<String, MessageAttributeValue>();
        notificationAttributes.put("AWS.SNS.MOBILE.BAIDU.DeployStatus",
                new MessageAttributeValue().withDataType("String")
                        .withStringValue("1"));
        notificationAttributes.put("AWS.SNS.MOBILE.BAIDU.MessageKey",
                new MessageAttributeValue().withDataType("String")
                        .withStringValue("default-channel-msg-key"));
        notificationAttributes.put("AWS.SNS.MOBILE.BAIDU.MessageType",
                new MessageAttributeValue().withDataType("String")
                        .withStringValue("0"));
        return notificationAttributes;
    }

    private static Map<String, MessageAttributeValue> addWNSNotificationAttributes() {
        Map<String, MessageAttributeValue> notificationAttributes = new HashMap<String, MessageAttributeValue>();
        notificationAttributes.put("AWS.SNS.MOBILE.WNS.CachePolicy",
                new MessageAttributeValue().withDataType("String")
                        .withStringValue("cache"));
        notificationAttributes.put("AWS.SNS.MOBILE.WNS.Type",
                new MessageAttributeValue().withDataType("String")
                        .withStringValue("wns/badge"));
        return notificationAttributes;
    }

    private static Map<String, MessageAttributeValue> addMPNSNotificationAttributes() {
        Map<String, MessageAttributeValue> notificationAttributes = new HashMap<String, MessageAttributeValue>();
        notificationAttributes.put("AWS.SNS.MOBILE.MPNS.Type",
                new MessageAttributeValue().withDataType("String")
                        .withStringValue("token")); // This attribute is required.
        notificationAttributes.put("AWS.SNS.MOBILE.MPNS.NotificationClass",
                new MessageAttributeValue().withDataType("String")
                        .withStringValue("realtime")); // This attribute is required.

        return notificationAttributes;
    }
}

EDIT 2:

enter image description here

EDIT 3:

I changed the following code to:

AmazonSNS sns = new AmazonSNSClient(new PropertiesCredentials(
        SNSMobilePush.class
                .getResourceAsStream("AwsCredentials.properties")));

to

AmazonSNS sns = new AmazonSNSClient(new BasicAWSCredentials("ACCESS_KEY_REPLACED",
                "SECRET_KEY_REPLACED"));

Now, there is a different error: Logcat

===========================================

Getting Started with Amazon SNS
===========================================

Exception in thread "main" java.lang.NoClassDefFoundError: org/xmlpull/v1/XmlPullParserException
    at com.amazonaws.services.sns.AmazonSNSClient.invoke(AmazonSNSClient.java:2263)
    at com.amazonaws.services.sns.AmazonSNSClient.createPlatformApplication(AmazonSNSClient.java:358)
    at com.test.tools.AmazonSNSClientWrapper.createPlatformApplication(AmazonSNSClientWrapper.java:49)
    at com.test.tools.AmazonSNSClientWrapper.demoNotification(AmazonSNSClientWrapper.java:119)
    at com.test.SNSMobilePush.demoAndroidAppNotification(SNSMobilePush.java:104)
    at com.test.SNSMobilePush.main(SNSMobilePush.java:71)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
Caused by: java.lang.ClassNotFoundException: org.xmlpull.v1.XmlPullParserException
    at java.net.URLClassLoader$1.run(URLClassLoader.java:372)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:360)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    ... 11 more

Process finished with exit code 1
like image 447
Vamsi Challa Avatar asked Oct 19 '22 04:10

Vamsi Challa


2 Answers

I'm using sns v2.2.5 :

build.gradle > compile 'com.amazonaws:aws-android-sdk-sns:2.2.5'

Here is my solution for subscribe/unsubscribe:

public class AmazonPushClient {

private static final String TAG = "AmazonPushClient";

private static final String PLATFORM_APPLICATION_ARN = "*****";
private static final String IDENTITY_POOL_ID = "******";

private AmazonSNSClient mClient;
private boolean isUnregistering;
private Application mApp;
private NotifPreferencesHelper mNotifPreferencesHelper;

public AmazonPushClient(Application application) {
    try {
        mApp = application;
        mClient = createPushClient(application);
        mNotifPreferencesHelper = new NotifPreferencesHelper(application);
    } catch (Exception e) {
        LOGE(TAG, "AmazonPushClient", e);
    }
}

@Nullable
private String token() {
    try {
        return InstanceID.getInstance(mApp).getToken(mApp.getString(R.string.gcm_defaultSenderId),
                GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
    } catch (Exception e) {
        LOGW(TAG, "token", e);
        return null;
    }
}

private CognitoCachingCredentialsProvider cognitoCachingCredentialsProvider(Application application) {
    return new CognitoCachingCredentialsProvider(
            application,
            IDENTITY_POOL_ID,
            Regions.EU_WEST_1 // if your identity_pool_id start with : eu-west-1
    );
}

private AmazonSNSClient createPushClient(Application application) {
    AmazonSNSClient client = new AmazonSNSClient(cognitoCachingCredentialsProvider(application));
    client.setRegion(Region.getRegion(Regions.EU_WEST_1));
    client.addRequestHandler(mHandler);
    return client;
}

public void pRegister() {
    synchronized (TAG) {
        LOGD(TAG, "registering");
        isUnregistering = true;
        String token = token();
        if(TextUtils.isEmpty(token)) {
            return;
        }
        mNotifPreferencesHelper.saveNotificationPreferences(true);
        CreatePlatformEndpointRequest platformEndpointRequest = new CreatePlatformEndpointRequest();
        platformEndpointRequest.setToken(token());
        platformEndpointRequest.setPlatformApplicationArn(PLATFORM_APPLICATION_ARN);
        CreatePlatformEndpointResult result = mClient.createPlatformEndpoint(platformEndpointRequest);
        mNotifPreferencesHelper.storeEndpointArn(result.getEndpointArn());
    }
}

public void pUnregister() {
    synchronized (TAG) {
        LOGD(TAG, "unregistering");
        isUnregistering = false;
        mNotifPreferencesHelper.saveNotificationPreferences(false);
        DeleteEndpointRequest deletePlatformApplicationRequest = new DeleteEndpointRequest();
        deletePlatformApplicationRequest.setEndpointArn(mNotifPreferencesHelper.getEndpointArn());
        mClient.deleteEndpoint(deletePlatformApplicationRequest);
    }
}

private RequestHandler2 mHandler = new RequestHandler2() {
    @Override
    public void beforeRequest(Request<?> request) {

    }

    @Override
    public void afterResponse(Request<?> request, Response<?> response) {
        if (isUnregistering) {
            mNotifPreferencesHelper.storeEndpointArn(null);
        }
    }

    @Override
    public void afterError(Request<?> request, Response<?> response, Exception e) {
    }
};

}

NotifPreferencesHelper is just something to store the EndpointARN. You have to use this class in a background thread

In association you have to implements GcmListenerService etc.. SNS is just for subscribe, not receive. https://developers.google.com/cloud-messaging/

like image 162
koni Avatar answered Oct 21 '22 22:10

koni


With respect to the Properties Credentials

A. Are you sure you are exporting the file in the build? Have you made sure you can access the file using regular file I/O outside of the credentials provider? Are you sure the file is formatted correctly (see https://github.com/aws/aws-sdk-android/blob/master/aws-android-sdk-core/src/main/java/com/amazonaws/auth/PropertiesCredentials.java) accessKey=KEY secretKey=SECRET Also looking at the source you should be able to load this file yourself using http://developer.android.com/reference/java/util/Properties.html.

However, I highly recommend not using this credentials provider. It is extremely unsafe in a mobile applications. Anyone could decompile your app and steal your credentials. A much safer approach is to use Amazon Cognito, which there is a plethora of examples. (Bottom of https://docs.aws.amazon.com/mobile/sdkforandroid/developerguide/setup.html , any of the examples here: https://docs.aws.amazon.com/mobile/sdkforandroid/developerguide/getting-started-android.html as well as samples in the GitHub repo https://github.com/awslabs/aws-sdk-android-samples

Cognito requires a little bit of set-up but the guides are tested, and it really doesn't take much more than a few minutes to be much more secure.

like image 43
WestonE Avatar answered Oct 21 '22 20:10

WestonE