📜 ⬆️ ⬇️

Connect FB, VK, G + to Android. Light version

I got a task in front of me - to make posting links from Android to a couple of social networks. Moreover, the most simple and easy - so as not to produce entities and bother as little as possible with tokens, sessions and so on. The task, indeed, is the minimum - only placing the link in the user's own account. If you can easily add descriptions or pictures to the link, you can do it, but do not rest.

For various reasons, Facebook, Vkontakte and Google+ were chosen. She planned to add Twitter, but by that time his Fabric had not yet been released, and we did not want to use a third-party library (see paragraph 2 below). I will add later.

As a result, the task for these three social networks turned out to be the following:
')
  1. The simplest software posting links interface.
  2. Use only native SDKs (for those reasons that this knowledge will come in handy later).
  3. Minimum code - only the most necessary for work.
  4. Everything should work regardless of whether the user has an installed social network client. But if it is - use the client dialog boxes.
  5. The user should receive a message about the success or no posting.
  6. It should be possible to programmatically respond to the successful placement of the record.


Solution Architecture


The variant with a separate library eventually turned out to be too cumbersome - the final code was about 250 lines, along with comments and empty lines. Moreover, everything was encapsulated in one class, which is quite simple to use.

Since a number of objects from the SDK still had to be built into the life cycle, a kind of container was needed - either Activity or Fragment. I chose a solution with an abstract Activity, because I needed to hang the posting commands on the ActionBar button. Moreover, do it for several Activities with different fragments inside.

In abstract Activity, I stitched up all the posting control code, and put out 3 methods outside, one for each grid. From this abstract activity itself, then inherited the rest of the Activity applications in which social networks were needed. In them, access to the necessary code was reduced to a method call from the parent class.

Everything described here can certainly be done with a fragment. Although somewhere I came across a message that embedding in the life cycle still needs to be done for the parent Activity. I do not know, I have not tried it.

So…

In order for the code described below to work, you need to connect your SDK to the project for each social network and register the application in the developers section. Everything is described here:

When developing, SDK descriptions were used on their social networking sites, articles on Habré and SO, ASNE library code (thanks to the author!)

Google+


The simplest code was logical solution for G +. All work with authentication and sessions is already built into the system. The desired dialog box (native from the client or the web if there is no client) is selected by itself, and it also reports the successful posting. Here, in the latter, the only ambush lay - the implementation of clause 6 of the requirements. To track the success of the publication, we had to add one constant and one conditional operator in onActivityResult:

private static final int GOOGLEPLUS_REQUEST_CODE = 1001; protected void onActivityResult(int requestCode, int resultCode, Intent data) { ... if ((requestCode == GOOGLEPLUS_REQUEST_CODE) && (resultCode == -1)) { //Do something if success } } 

The posting procedure itself:

  /** * Publish link in Google+ * @param text - message about link (may be changed or deleted by user) * @param link - http:// etc */ public final void googleplusPublish(String text, String link) { Intent shareIntent = new PlusShare.Builder(this) .setType("text/plain") .setText(text) .setContentUrl(Uri.parse(link)) .getIntent(); startActivityForResult(shareIntent, GOOGLEPLUS_REQUEST_CODE); } 

Facebook


C Facebook had to tinker a little longer, and not all the requirements could be implemented.

Happened:

Did not work out:

What's in the code ...

First of all, you need to add an application ID in string.xml and enter metadata in the manifest (do not forget to allow access to the Internet - this is necessary for all networks!):

  <meta-data android:name="com.facebook.sdk.ApplicationId" android:value="@string/facebook_app_id"/> 

For work, you will need an auxiliary object that quite tightly “sits down” on the methods of the life cycle. It is needed for posting by the native client, if it is installed. It would be possible, of course, to do only the web, but without sessions, it requires entering a password every time, which is very annoying. And annoying the user once again is not good ...

Tracking the success of the publication also had to write with pens. This is where the bjaka with the client got out:

  private UiLifecycleHelper fbUIHelper; protected void onCreate(Bundle savedInstanceState) { ... fbUIHelper = new UiLifecycleHelper(this, null); fbUIHelper.onCreate(savedInstanceState); } protected void onActivityResult(int requestCode, int resultCode, Intent data) { ... fbUIHelper.onActivityResult(requestCode, resultCode, data, new FacebookDialog.Callback() { //Listener for Facebook-client if installed @Override public void onError(FacebookDialog.PendingCall pendingCall, Exception error, Bundle data) { toastMessage("  "); } @Override public void onComplete(FacebookDialog.PendingCall pendingCall, Bundle data) { toastMessage("     ,   "); } }); protected void onResume() { ... fbUIHelper.onResume(); } protected void onSaveInstanceState(Bundle outState) { ... fbUIHelper.onSaveInstanceState(outState); } protected void onPause() { ... fbUIHelper.onPause(); } protected void onDestroy() { ... fbUIHelper.onDestroy(); } 

The very code of the method that will be used by the child classes is as follows:

  /** * Publish link in FaceBook * @param name - title of block * @param caption - text on bottom of block * @param description - description of link (between title and caption) * @param link - http:// etc * @param pictureLink - http:// etc - link on image in web */ public final void facebookPublish(String name, String caption, String description, String link, String pictureLink) { if (FacebookDialog.canPresentShareDialog(getApplicationContext(), FacebookDialog.ShareDialogFeature.SHARE_DIALOG)) { //Facebook-client is installed FacebookDialog shareDialog = new FacebookDialog.ShareDialogBuilder(this) .setName(name) .setCaption(caption) .setDescription(description) .setLink(link) .setPicture(pictureLink) .build(); fbUIHelper.trackPendingDialogCall(shareDialog.present()); } else { //Facebook-client is not installed – use web-dialog Bundle params = new Bundle(); params.putString("name", name); params.putString("caption", caption); params.putString("description", description); params.putString("link", link); params.putString("picture", pictureLink); WebDialog feedDialog = new WebDialog.FeedDialogBuilder(this, Utility.getMetadataApplicationId(this), params) .setOnCompleteListener(new OnCompleteListener() { //Listener for web-dialog @Override public void onComplete(Bundle values, FacebookException error) { if ((values != null) && (values.getString("post_id") != null) && (error == null)) { toastMessage(" "); } else { toastMessage("  "); }; }; }) .build(); feedDialog.show(); } } 

In contact with


Perhaps the most terrible documentation. Had pretty sweat. Moreover, it was not possible to completely get rid of the use of tokens - without them in any way. But in order ...

Here, too, will have to get into the manifest for the sake of one line of code:

  <activity android:name="com.vk.sdk.VKOpenAuthActivity"/> 

The docks say softly that “ it is worth adding, otherwise there may be problems with the launch of the authorization activity ”, but if the user does not have a VK client, the application will crash with an ActivityNotFoundException error.

In the very class at the very beginning, you need to add a code to store the ID, access rights and authorization management:

  private String appId = "1234567"; // Need to change to real app_id private static String vkTokenKey = "VK_ACCESS_TOKEN"; private static String[] vkScope = new String[]{VKScope.WALL}; private final VKSdkListener vkSdkListener = new VKSdkListener() { @Override public void onCaptchaError(VKError captchaError) { new VKCaptchaDialog(captchaError).show(); } @Override public void onTokenExpired(VKAccessToken expiredToken) { VKSdk.authorize(vkScope, true, false); } @Override public void onAccessDenied(VKError authorizationError) { new AlertDialog.Builder(SocialNetworkActivity.this) .setMessage(authorizationError.errorMessage) .show(); } @Override public void onReceiveNewToken(VKAccessToken newToken) { newToken.saveTokenToSharedPreferences(getApplicationContext(), vkTokenKey); } }; 

Into the methods of the life cycle of Activity, this infection also penetrates deeply, although not as much as FB:

  protected void onCreate(Bundle savedInstanceState) { ... VKUIHelper.onCreate(this); VKSdk.initialize(vkSdkListener, appId, VKAccessToken.tokenFromSharedPreferences(this, vkTokenKey)); } protected void onActivityResult(int requestCode, int resultCode, Intent data) { ... VKUIHelper.onActivityResult(this, requestCode, resultCode, data); } protected void onResume() { ... VKUIHelper.onResume(this); } protected void onDestroy() { ... VKUIHelper.onDestroy(this); } 

However, when publishing a link, you will have to force the user to first log in and then re-press the publish button. This is bad in terms of usability, but I haven’t found another option. A token issued once seemed to last for about an hour. It is hemorrhoid, but no worse than registration at every posting, as in the web dialog of FB.

Another ambush hid where I did not expect the bases. When debugging from Eclipse on a real device, everything worked like a clock. But as soon as I installed the same application from Google Pleya, the VK client began to curse when posting a link:

{"Error": "invalid_request", "error_description": "sdk_fingerprint is incorrect"}

In this case, the authorization is successful, and the same application without VK client through the web works fine. Those. fingerprint correct. I suspect a client glitch. Or not a glitch, but an intentionally closed possibility, which is quite likely looking at this link here (towards the end). I will understand further, but if someone in the know and can help - I will be grateful.

Another unresolved question is why the link title, visible in the preview window, is lost when it is published. The answer did not find, alas. Also I would be grateful for the tips.

Posting code itself:

  /** * Publish link in Vkontakte * @param message - message about link (may be changed or deleted by user) * @param link - http:// etc * @param linkName - title of link - not published (don't know why...) */ public final void vkontaktePublish(String message, String link, String linkName) { VKAccessToken token = VKAccessToken.tokenFromSharedPreferences(this, vkTokenKey); if ((token == null) || token.isExpired()) { VKSdk.authorize(vkScope, true, false); toastMessage(" .     "); } else { new VKShareDialog() .setText(message) .setAttachmentLink(linkName, link) .setShareDialogListener(new VKShareDialog.VKShareDialogListener() { @Override public void onVkShareComplete(int postId) { toastMessage(" "); } @Override public void onVkShareCancel() { toastMessage("  "); } }).show(getSupportFragmentManager(), "VK_SHARE_DIALOG"); } } 

I wrote the application under the Support Library, so the code uses getSupportFragmentManager. For versions 3.0+, you need to replace it with a call to the native method.

Code usage


Well, in short, that's all. Now we inherit the desired Activity from this one and where it is required we use the xxxxPublish () calls. You can hang the buttons, but you can on the popup menu in ActionBar (although in this case the call will not be very beautiful, but the menu itself is working):

  public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_share: View view = findViewById(R.id.action_share); showPopupMenu(view, "https://play.google.com/store/apps/details?id=ru.fantaversum.taleidoscope", " -   ", "  Google Play", "      -     .   .  .", "http://www.taleidoscope.ru/images/fb_logo.png", ":  -  .       -     .   .  .", "  Google Play"); break; } return super.onOptionsItemSelected(item); } 

  public void showPopupMenu(View view, final String link, final String fb_name, final String fb_caption, final String fb_description, final String fb_pictureLink, final String message, final String linkName) { PopupMenu popup = new PopupMenu(this, view); popup.getMenuInflater().inflate(R.menu.popup, popup.getMenu()); popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem menuItem) { switch (menuItem.getItemId()) { case R.id.menu_facebook: facebookPublish(fb_name, fb_caption, fb_description, link, fb_pictureLink); return true; case R.id.menu_vkontakte: vkontaktePublish(message, link, linkName); return true; case R.id.menu_googleplus: googleplusPublish(message, link); return true; } return false; } }); popup.show(); } 

The source code of the whole Activity can be downloaded here .

Source: https://habr.com/ru/post/243411/


All Articles