{"_id":"5a6b684793313c005b692e0e","category":{"_id":"5a6b684793313c005b692e08","version":"5a6b684793313c005b692e07","project":"57c87ef85754fa1700b1228d","__v":0,"sync":{"url":"","isSync":false},"reference":false,"createdAt":"2015-09-18T01:38:20.281Z","from_sync":false,"order":0,"slug":"getting-started","title":"Getting Started"},"user":"57c73a03e6935b1700b15115","parentDoc":null,"project":"57c87ef85754fa1700b1228d","version":{"_id":"5a6b684793313c005b692e07","project":"57c87ef85754fa1700b1228d","__v":1,"createdAt":"2018-01-26T17:41:27.297Z","releaseDate":"2018-01-26T17:41:27.297Z","categories":["5a6b684793313c005b692e08","5a6b684793313c005b692e09","5a6b684793313c005b692e0a","5a6b684793313c005b692e0b"],"is_deprecated":false,"is_hidden":false,"is_beta":false,"is_stable":true,"codename":"","version_clean":"3.5.3","version":"3.5.3"},"__v":0,"updates":[],"next":{"pages":[],"description":""},"createdAt":"2017-05-04T21:23:35.731Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":2,"body":"[block:api-header]\n{\n  \"title\": \"Create User-managed Activity\"\n}\n[/block]\nCreate an Activity that extends from **AbstractPrimerWithUserActivity** if your app requires users to login or signup before they use your product. You can imagine this Activity as a 'pass-through' Activity that your user must go through in order to signup or login. \n\nYou must implement the following required methods for this Activity. \n\n- `int getSplashLayoutResId()` - Must return a layout resource identifier. Primer will inflate this resource and display it to the user when we are loading our data. It should resemble a splash screen.\n\n- `String getCurrentUserId()` - Should return a String representing the user ID of the current user. If there is no user logged in yet, then return null. \n\n- `void handlePrimerComplete(String primerUserId)` -  After we are finished showing (or skipping) Primer screens, we call this method to allow you to navigate away from this Activity. We pass in the current user id that we have so you can determine where to go next. If this is empty, then you will want to start your native login/signup Activity.\n\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"/**\\n * Launch activity that facilitates the login/signup of a user.\\n */\\npublic class LaunchActivity extends AbstractPrimerWithUserActivity {\\n\\n   /**\\n     * :::at:::return - The resource ID of the layout to use for the splash screen.\\n     */\\n    @Override\\n    protected int getSplashLayoutResId() {\\n        return R.layout.splash;\\n    }\\n  \\n    /**\\n       Primer is finished. You should navigate away from this activity \\n       based on the current state of your user. \\n       We pass in our internal user id so you know if \\n       Primer successfully signed someone up.\\n     */\\n    @Override\\n    protected void handlePrimerComplete(String primerUserId) {\\n        if (primerUserId == null) {\\n            //start an Activity to login/signup the user natively\\n        } else {\\n            //start your 'main' Activity\\n        }\\n        finish();\\n    }\\n  \\n    /**\\n     * This override will assist the Primer SDK in supporting\\n     * the first app launch of a user who is already logged into \\n     * our system, but is not yet logged into Primer's system.\\n     */\\n    @Nullable\\n    @Override\\n    protected String getCurrentUserId() {\\n        if (UserManager.isLoggedIn()) {\\n            return UserManager.getCurrentUserId();\\n        }\\n        return null;\\n    }\\n}\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nDon't forget to add this new Activity to your app's Manifest.xml file.  \n\n- All of our layouts are optimized for Portrait only. Lock the orientation to `portrait` only.\n- There should only be one instance of this Activity in a task, so configure the `launchMode` to `singleTask`\n- We provide a custom Theme for this Activity which assist the presentation of our screens. This is not required, and you can duplicate it and edit if you desire. \n- Make sure that the Activity does not declare noHistory == true\n\nThe configuration below will place Primer as the launch Activity. \n\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"<activity android:name=\\\".LaunchActivity\\\"\\n          android:launchMode=\\\"singleTask\\\"\\n          android:screenOrientation=\\\"portrait\\\"\\n          android:theme=\\\"@style/PrimerFull\\\"\\n          android:label=\\\"YOUR_APP_LABEL\\\"\\n          android:noHistory=\\\"false\\\"\\n          android:windowSoftInputMode=\\\"adjustPan\\\">\\n          <intent-filter>\\n                <action android:name=\\\"android.intent.action.MAIN\\\"/>\\n                <category android:name=\\\"android.intent.category.LAUNCHER\\\"/>\\n          </intent-filter>\\n</activity>\",\n      \"language\": \"xml\"\n    }\n  ]\n}\n[/block]\n\n[block:callout]\n{\n  \"type\": \"info\",\n  \"body\": \"Be sure to audit your MAIN and LAUNCHER intent filters when adding this Activity to your manifest. (Ensure you only want one launcher Activity.) Also ensure that you property refactor any install events or other things that were driven by your previous launch activity. \\n\\nAlso ensure that the launch mode is singleTask.\"\n}\n[/block]\n\n[block:api-header]\n{\n  \"title\": \"Flows Launched!\"\n}\n[/block]\nBuild and run your application to see the automatic Primer onboarding experience!\nYou can design and edit your flows easily on the Dashboard.\n\n[block:callout]\n{\n  \"type\": \"warning\",\n  \"body\": \"Go to the Dashboard and ensure that your organic flow is currently running. If it isn't, no flow will appear on initialization.\",\n  \"title\": \"Not seeing anything appear?\"\n}\n[/block]\n\n[block:api-header]\n{\n  \"title\": \"Authentication\"\n}\n[/block]\nTo hook up the signup and login actions to your system, override the following methods in the Primer Activity. These are all optional overrides. You may have to refactor your existing signup/login APIs to support being used in two different locations in your codebase. \n\n1. [Hook up Signup](#1-hook-up-signup)\n2. [Hook up Login](#2-hook-up-login)\n3. [Hook up Logout](#3-hook-up-logout)\n4. [Hook up Password Recovery](#4-hook-up-password-recovery)\n5. [Hook up Screen Validation](#5-hook-up-screen-validation)\n\nIf you want to add Facebook Login functionality:\n\n6. [Hook up Facebook Login](#6-hook-up-facebook-login)\n\nTo see more detailed documentation about authentication, please see our [Detailed Authentication Guide](doc:authentication) section.\n\nNeed help or have questions? Contact us at <a href=\"mailto:success@goprimer.com\">success@goprimer.com</a>\n[block:api-header]\n{\n  \"title\": \"1. Hook up Signup\"\n}\n[/block]\nWhen a signup flow is submitted, Primer will call the `signUpWithFields` method. The parameters include a `Map<String, Object>` which contains all fields of the flow. Note that the non-sensitive fields get added as user properties after a successful validation. The types of Objects in the map are java.util.String, java.util.List<String>, and java.util.Calendar. Note: even if you do not want to validate any fields with signup, you must respond to the callback in order to let Primer continue with the flow. \nIn this method you should validate that a new user with the given fields can be created, and if so you should save it to your user system. If this succeeds pass the user identifier as the second parameter of the callback. If the signup process fails, pass an invalidated result as the first parameter. \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"@Override\\npublic void signUpWithFields(Map<String, Object> allFieldsMap, UserValidationCallback callback) {\\n    asyncSignupMethod(allFieldsMap, new AsyncFakeCallback() {\\n        @Override\\n        void onSuccess(String userId) {\\n            callback.submit(null, userId);\\n        }\\n\\n        @Override\\n        void onFailure() {\\n            ValidationResult result = new ValidationResult();\\n            result.invalidateWithErrorMessage(\\\"custom error message\\\");\\n            callback.submit(result, null);\\n        }\\n    });\\n}\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\n\n[block:api-header]\n{\n  \"title\": \"2. Hook up Login\"\n}\n[/block]\nWhen a login flow is submitted, Primer will call the `logInWithFields` method. The `Map<String, Object>` contains all fields of the flow. Note that the non-sensitive fields get added as user properties after a successful validation. Note: even if you do not want to validate any fields with login, you must respond to the callback in order to let Primer continue with the flow. \nIn this method you should validate that a user can be logged in with the given fields, and if so you should save that state to your user system. Handle validation similarly like in the signup method.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"@Override\\npublic void logInWithFields(Map<String, Object> allFieldsMap, UserValidationCallback callback) {\\n    Object userId = allFieldsMap.get(\\\"userid\\\");\\n\\n    if (userId == null) {\\n        userId = \\\"userID\\\";\\n    }\\n  \\n  \\tasyncLoginMethod(allFieldsMap, new AsyncFakeCallback() {\\n        @Override\\n        void onSuccess(String userId) {\\n            callback.submit(null, userId);\\n        }\\n\\n        @Override\\n        void onFailure() {\\n            ValidationResult result = new ValidationResult();\\n            result.invalidateWithErrorMessage(\\\"custom error message\\\");\\n            callback.submit(result, null);\\n        }\\n    });\\n}\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\n\n[block:api-header]\n{\n  \"title\": \"3. Hook up Logout\"\n}\n[/block]\nWhen your user logs out of your system, you must also inform our SDK about the it. Simply call `Primer.logout()`. Doing so resets all state information, user properties, and Facebook sessions. Keep your existing implementation for sending the user to your logged out activity. \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"Primer.logout();\\n\\n//start your existing Login activity\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\n\n[block:api-header]\n{\n  \"title\": \"4. Hook up Password Recovery\"\n}\n[/block]\nWhen a recover password flow is submitted Primer calls the `recoverPasswordsWithFields` method. The `Map<String, Object>` contains all fields of the flow. Note: even if you do not want to validate any fields, you must respond to the callback in order to let Primer continue with the flow. \nIn this method you should try to send out a password recovery email to the user. If this succeeds pass in null (or a new, valid result instance) as the parameter of the completion block. If the process fails, pass an invalidated result as the parameter.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"@Override\\npublic void recoverPasswordsWithFields(Map<String, Object> allFieldsMap, ResetPasswordCallback callback) {\\n    asyncSendResetPasswordEmail(allFieldsMap, new AsyncFakeCallback() {\\n        @Override\\n        public void onSuccess() {\\n            // password reset email sent\\n            callback.submit(null);\\n        }\\n\\n        @Override\\n        public void onError(FakeResetPasswordError error) {\\n            ValidationResult result = new ValidationResult();\\n            result.invalidateWithErrorMessage(error.getMessage());\\n            callback.submit(result);\\n        }\\n    });\\n}\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\n\n[block:api-header]\n{\n  \"title\": \"5. Hook up Screen Validation\"\n}\n[/block]\nTo validate any input fields on a screen, implement the `validateFields` method. It gets called after a screen is submitted with any inputs on it. The `Map<String, Object>` contains all fields of the screen. Note: even if you do not want to validate the fields, you must respond to the callback in order to let Primer continue with the flow. \nHandle the process similarly like in the recover password scenario, if it succeeds pass in null (or a new, valid result instance) as the parameter of the completion block. If the process fails, pass an invalidated result as the parameter.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"@Override\\npublic void validateFields(Map<String, Object> allFieldsMap, ValidationCallback validationCallback) {\\n    validationCallback.submit(new ValidationResult());\\n}\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\n\n[block:api-header]\n{\n  \"title\": \"6. Hook up Facebook Login\"\n}\n[/block]\nIf your application has the v4+ version of the Facebook Android SDK integrated and you'd like to set Facebook Login up as part of the Primer onboarding experience, it's easy to do so.\n\nIn case you don't have their SDK integrated yet, just follow their [Getting Started] (https://developers.facebook.com/docs/android/getting-started) guide.\n\nIn order for Facebook login to work, you must override the `authenticateFacebookWithFields` method. The Map<String, Object> contains all requested Graph API fields that Facebook returned to the SDK. Note that these fields get added as user properties after a successful validation. Even if you do not want to validate anything with Facebook, you must respond to the callback in order to let Primer continue with the flow. \n\nIn this method you should validate that a new user with the given fields can be created, and if so you should save it to your user system. If this succeeds, pass the user identifier as the second parameter of the callback. If the process fails, pass an invalidated result as the first parameter. The final parameter is a boolean representing whether or not the user was signed up vs logged in. If the user was signed up, then pass in true. If the user was simply logged in, then pass in false. \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"@Override\\npublic void authenticateFacebookWithFields(Map<String, Object> allFieldsMap, FacebookUserValidationCallback callback) {\\n    String identifier = (String) allFieldsMap.get(\\\"id\\\");\\n    callback.submit(new ValidationResult(), identifier, isSignup);\\n}\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\n\n[block:api-header]\n{\n  \"title\": \"You're done\"\n}\n[/block]\nCongratulations, You now have authentication implemented!","excerpt":"","slug":"user_activity","type":"basic","title":"User Required Onboarding"}

User Required Onboarding


[block:api-header] { "title": "Create User-managed Activity" } [/block] Create an Activity that extends from **AbstractPrimerWithUserActivity** if your app requires users to login or signup before they use your product. You can imagine this Activity as a 'pass-through' Activity that your user must go through in order to signup or login. You must implement the following required methods for this Activity. - `int getSplashLayoutResId()` - Must return a layout resource identifier. Primer will inflate this resource and display it to the user when we are loading our data. It should resemble a splash screen. - `String getCurrentUserId()` - Should return a String representing the user ID of the current user. If there is no user logged in yet, then return null. - `void handlePrimerComplete(String primerUserId)` - After we are finished showing (or skipping) Primer screens, we call this method to allow you to navigate away from this Activity. We pass in the current user id that we have so you can determine where to go next. If this is empty, then you will want to start your native login/signup Activity. [block:code] { "codes": [ { "code": "/**\n * Launch activity that facilitates the login/signup of a user.\n */\npublic class LaunchActivity extends AbstractPrimerWithUserActivity {\n\n /**\n * @return - The resource ID of the layout to use for the splash screen.\n */\n @Override\n protected int getSplashLayoutResId() {\n return R.layout.splash;\n }\n \n /**\n Primer is finished. You should navigate away from this activity \n based on the current state of your user. \n We pass in our internal user id so you know if \n Primer successfully signed someone up.\n */\n @Override\n protected void handlePrimerComplete(String primerUserId) {\n if (primerUserId == null) {\n //start an Activity to login/signup the user natively\n } else {\n //start your 'main' Activity\n }\n finish();\n }\n \n /**\n * This override will assist the Primer SDK in supporting\n * the first app launch of a user who is already logged into \n * our system, but is not yet logged into Primer's system.\n */\n @Nullable\n @Override\n protected String getCurrentUserId() {\n if (UserManager.isLoggedIn()) {\n return UserManager.getCurrentUserId();\n }\n return null;\n }\n}", "language": "java" } ] } [/block] Don't forget to add this new Activity to your app's Manifest.xml file. - All of our layouts are optimized for Portrait only. Lock the orientation to `portrait` only. - There should only be one instance of this Activity in a task, so configure the `launchMode` to `singleTask` - We provide a custom Theme for this Activity which assist the presentation of our screens. This is not required, and you can duplicate it and edit if you desire. - Make sure that the Activity does not declare noHistory == true The configuration below will place Primer as the launch Activity. [block:code] { "codes": [ { "code": "<activity android:name=\".LaunchActivity\"\n android:launchMode=\"singleTask\"\n android:screenOrientation=\"portrait\"\n android:theme=\"@style/PrimerFull\"\n android:label=\"YOUR_APP_LABEL\"\n android:noHistory=\"false\"\n android:windowSoftInputMode=\"adjustPan\">\n <intent-filter>\n <action android:name=\"android.intent.action.MAIN\"/>\n <category android:name=\"android.intent.category.LAUNCHER\"/>\n </intent-filter>\n</activity>", "language": "xml" } ] } [/block] [block:callout] { "type": "info", "body": "Be sure to audit your MAIN and LAUNCHER intent filters when adding this Activity to your manifest. (Ensure you only want one launcher Activity.) Also ensure that you property refactor any install events or other things that were driven by your previous launch activity. \n\nAlso ensure that the launch mode is singleTask." } [/block] [block:api-header] { "title": "Flows Launched!" } [/block] Build and run your application to see the automatic Primer onboarding experience! You can design and edit your flows easily on the Dashboard. [block:callout] { "type": "warning", "body": "Go to the Dashboard and ensure that your organic flow is currently running. If it isn't, no flow will appear on initialization.", "title": "Not seeing anything appear?" } [/block] [block:api-header] { "title": "Authentication" } [/block] To hook up the signup and login actions to your system, override the following methods in the Primer Activity. These are all optional overrides. You may have to refactor your existing signup/login APIs to support being used in two different locations in your codebase. 1. [Hook up Signup](#1-hook-up-signup) 2. [Hook up Login](#2-hook-up-login) 3. [Hook up Logout](#3-hook-up-logout) 4. [Hook up Password Recovery](#4-hook-up-password-recovery) 5. [Hook up Screen Validation](#5-hook-up-screen-validation) If you want to add Facebook Login functionality: 6. [Hook up Facebook Login](#6-hook-up-facebook-login) To see more detailed documentation about authentication, please see our [Detailed Authentication Guide](doc:authentication) section. Need help or have questions? Contact us at <a href="mailto:success@goprimer.com">success@goprimer.com</a> [block:api-header] { "title": "1. Hook up Signup" } [/block] When a signup flow is submitted, Primer will call the `signUpWithFields` method. The parameters include a `Map<String, Object>` which contains all fields of the flow. Note that the non-sensitive fields get added as user properties after a successful validation. The types of Objects in the map are java.util.String, java.util.List<String>, and java.util.Calendar. Note: even if you do not want to validate any fields with signup, you must respond to the callback in order to let Primer continue with the flow. In this method you should validate that a new user with the given fields can be created, and if so you should save it to your user system. If this succeeds pass the user identifier as the second parameter of the callback. If the signup process fails, pass an invalidated result as the first parameter. [block:code] { "codes": [ { "code": "@Override\npublic void signUpWithFields(Map<String, Object> allFieldsMap, UserValidationCallback callback) {\n asyncSignupMethod(allFieldsMap, new AsyncFakeCallback() {\n @Override\n void onSuccess(String userId) {\n callback.submit(null, userId);\n }\n\n @Override\n void onFailure() {\n ValidationResult result = new ValidationResult();\n result.invalidateWithErrorMessage(\"custom error message\");\n callback.submit(result, null);\n }\n });\n}", "language": "java" } ] } [/block] [block:api-header] { "title": "2. Hook up Login" } [/block] When a login flow is submitted, Primer will call the `logInWithFields` method. The `Map<String, Object>` contains all fields of the flow. Note that the non-sensitive fields get added as user properties after a successful validation. Note: even if you do not want to validate any fields with login, you must respond to the callback in order to let Primer continue with the flow. In this method you should validate that a user can be logged in with the given fields, and if so you should save that state to your user system. Handle validation similarly like in the signup method. [block:code] { "codes": [ { "code": "@Override\npublic void logInWithFields(Map<String, Object> allFieldsMap, UserValidationCallback callback) {\n Object userId = allFieldsMap.get(\"userid\");\n\n if (userId == null) {\n userId = \"userID\";\n }\n \n \tasyncLoginMethod(allFieldsMap, new AsyncFakeCallback() {\n @Override\n void onSuccess(String userId) {\n callback.submit(null, userId);\n }\n\n @Override\n void onFailure() {\n ValidationResult result = new ValidationResult();\n result.invalidateWithErrorMessage(\"custom error message\");\n callback.submit(result, null);\n }\n });\n}", "language": "java" } ] } [/block] [block:api-header] { "title": "3. Hook up Logout" } [/block] When your user logs out of your system, you must also inform our SDK about the it. Simply call `Primer.logout()`. Doing so resets all state information, user properties, and Facebook sessions. Keep your existing implementation for sending the user to your logged out activity. [block:code] { "codes": [ { "code": "Primer.logout();\n\n//start your existing Login activity", "language": "java" } ] } [/block] [block:api-header] { "title": "4. Hook up Password Recovery" } [/block] When a recover password flow is submitted Primer calls the `recoverPasswordsWithFields` method. The `Map<String, Object>` contains all fields of the flow. Note: even if you do not want to validate any fields, you must respond to the callback in order to let Primer continue with the flow. In this method you should try to send out a password recovery email to the user. If this succeeds pass in null (or a new, valid result instance) as the parameter of the completion block. If the process fails, pass an invalidated result as the parameter. [block:code] { "codes": [ { "code": "@Override\npublic void recoverPasswordsWithFields(Map<String, Object> allFieldsMap, ResetPasswordCallback callback) {\n asyncSendResetPasswordEmail(allFieldsMap, new AsyncFakeCallback() {\n @Override\n public void onSuccess() {\n // password reset email sent\n callback.submit(null);\n }\n\n @Override\n public void onError(FakeResetPasswordError error) {\n ValidationResult result = new ValidationResult();\n result.invalidateWithErrorMessage(error.getMessage());\n callback.submit(result);\n }\n });\n}", "language": "java" } ] } [/block] [block:api-header] { "title": "5. Hook up Screen Validation" } [/block] To validate any input fields on a screen, implement the `validateFields` method. It gets called after a screen is submitted with any inputs on it. The `Map<String, Object>` contains all fields of the screen. Note: even if you do not want to validate the fields, you must respond to the callback in order to let Primer continue with the flow. Handle the process similarly like in the recover password scenario, if it succeeds pass in null (or a new, valid result instance) as the parameter of the completion block. If the process fails, pass an invalidated result as the parameter. [block:code] { "codes": [ { "code": "@Override\npublic void validateFields(Map<String, Object> allFieldsMap, ValidationCallback validationCallback) {\n validationCallback.submit(new ValidationResult());\n}", "language": "java" } ] } [/block] [block:api-header] { "title": "6. Hook up Facebook Login" } [/block] If your application has the v4+ version of the Facebook Android SDK integrated and you'd like to set Facebook Login up as part of the Primer onboarding experience, it's easy to do so. In case you don't have their SDK integrated yet, just follow their [Getting Started] (https://developers.facebook.com/docs/android/getting-started) guide. In order for Facebook login to work, you must override the `authenticateFacebookWithFields` method. The Map<String, Object> contains all requested Graph API fields that Facebook returned to the SDK. Note that these fields get added as user properties after a successful validation. Even if you do not want to validate anything with Facebook, you must respond to the callback in order to let Primer continue with the flow. In this method you should validate that a new user with the given fields can be created, and if so you should save it to your user system. If this succeeds, pass the user identifier as the second parameter of the callback. If the process fails, pass an invalidated result as the first parameter. The final parameter is a boolean representing whether or not the user was signed up vs logged in. If the user was signed up, then pass in true. If the user was simply logged in, then pass in false. [block:code] { "codes": [ { "code": "@Override\npublic void authenticateFacebookWithFields(Map<String, Object> allFieldsMap, FacebookUserValidationCallback callback) {\n String identifier = (String) allFieldsMap.get(\"id\");\n callback.submit(new ValidationResult(), identifier, isSignup);\n}", "language": "java" } ] } [/block] [block:api-header] { "title": "You're done" } [/block] Congratulations, You now have authentication implemented!