Can I share to my NativeScript app?
Asked Answered
S

6

5

Is it possible in current state of NativeScript to create an app which listens for share intents on Android?

What I would like to achieve is for example having a website opened in my web browser on Android, tap on share and see my NativeScript app on the list of share targets.

I did accomplish this on a native Android app but can't get it to work in a NativeScript app. I've messed with the AndroidManifest.xml to add

<action android:name="android.intent.action.SEND"></action>
<category android:name="android.intent.category.DEFAULT"></category>

into intent-filter but this did not help. My app does not show up in the list of share targets.

Snakemouth answered 29/5, 2016 at 21:19 Comment(0)
R
2

NativeScript should support this scenario out of the box. Here's what my AndroidManifest in app/App_resources/Android of a default bootstrapped application looks like:

<activity
        android:name="com.tns.NativeScriptActivity"
        android:label="@string/title_activity_kimera"
        android:configChanges="keyboardHidden|orientation|screenSize">

        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
        <intent-filter> 
            <action android:name="android.intent.action.SEND" />
            <category android:name="android.intent.category.DEFAULT" />
            <data android:mimeType="text/plain" />
       </intent-filter>
</activity>

edit: Very simple implementation to send intent to any of my other application:

FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent sendIntent = new Intent(Intent.ACTION_SEND);
                sendIntent.setType("text/plain");
                sendIntent.putExtra("string", "the data Im sending you");

                Intent chooser = Intent.createChooser(sendIntent, "Share with ");

                if (sendIntent.resolveActivity(getPackageManager()) != null) {
                    startActivity(chooser);
                }
            }
        });
Roundworm answered 1/6, 2016 at 7:56 Comment(3)
I must have mixed something up in my code cause it actually works with your example. I'm not sure how to use this Java snippet in my project but I don't need to send intents from my app yet. Thanks @Roundworm !Snakemouth
The second code snippet is a sample code, demonstrating how an intent can be sent, which you could use in an Android application, or to access the native Android API through JavaScript in a NativeScript application (docs.nativescript.org/runtimes/android/generator/…).Roundworm
Is there a way to mimic this same functionality on ios?Arsis
C
3

I've been searching for a solution to this question myself and found all of the others answers here very helpful.

Yet, I'm a noob (only two days in) for NativeScript and couldn't actually get where and how to implement all the code bits together to work.

By using the answers here I could continue my search and found a finished GITHUB EXAMPLE: NickIliev/nativescript-receiving-shared-content

For other freshmen (or freshwoman) looking for a finished example go to the repo and explore the code in /demo/app/ directory. It was helpful for me and I'll hope it will help you too.

Contreras answered 9/5, 2019 at 7:26 Comment(0)
R
2

NativeScript should support this scenario out of the box. Here's what my AndroidManifest in app/App_resources/Android of a default bootstrapped application looks like:

<activity
        android:name="com.tns.NativeScriptActivity"
        android:label="@string/title_activity_kimera"
        android:configChanges="keyboardHidden|orientation|screenSize">

        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
        <intent-filter> 
            <action android:name="android.intent.action.SEND" />
            <category android:name="android.intent.category.DEFAULT" />
            <data android:mimeType="text/plain" />
       </intent-filter>
</activity>

edit: Very simple implementation to send intent to any of my other application:

FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent sendIntent = new Intent(Intent.ACTION_SEND);
                sendIntent.setType("text/plain");
                sendIntent.putExtra("string", "the data Im sending you");

                Intent chooser = Intent.createChooser(sendIntent, "Share with ");

                if (sendIntent.resolveActivity(getPackageManager()) != null) {
                    startActivity(chooser);
                }
            }
        });
Roundworm answered 1/6, 2016 at 7:56 Comment(3)
I must have mixed something up in my code cause it actually works with your example. I'm not sure how to use this Java snippet in my project but I don't need to send intents from my app yet. Thanks @Roundworm !Snakemouth
The second code snippet is a sample code, demonstrating how an intent can be sent, which you could use in an Android application, or to access the native Android API through JavaScript in a NativeScript application (docs.nativescript.org/runtimes/android/generator/…).Roundworm
Is there a way to mimic this same functionality on ios?Arsis
L
2

In addition to the intent-filter you have to add in your AppManifest.xml make sure that you rebuild your app (livesync option may not reflect changes in AppManifest.xml)

Here is an NativeScript implementation for basic share

var app = require("application");

function onShare() {

    var sharingIntent = new android.content.Intent(android.content.Intent.ACTION_SEND);
    sharingIntent.setType("text/plain");
    var shareBody = "Here is the share content body";

    sharingIntent.addFlags(android.content.Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
    sharingIntent.addFlags(android.content.Intent.FLAG_ACTIVITY_NEW_TASK | android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK);

    sharingIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, "Subject Here");
    sharingIntent.putExtra(android.content.Intent.EXTRA_TEXT, shareBody);

    app.android.context.startActivity(sharingIntent);
}
exports.onShare = onShare;
Lieselotteliestal answered 1/6, 2016 at 13:3 Comment(1)
Thanks @nick-iliev :)Snakemouth
S
1

First update your AndroidManifest.xml in app/App_Resources/AndroidManifest.xml

Add following intent-filter like below

<application        android:name="com.tns.NativeScriptApplication"      android:allowBackup="true"      android:icon="@drawable/icon"       android:label="@string/app_name"
                android:theme="@style/AppTheme">        <activity           android:name="com.tns.NativeScriptActivity"
                        android:label="@string/title_activity_kimera"           android:configChanges="keyboardHidden|orientation|screenSize">

                        <intent-filter>
                <action android:name="android.intent.action.MAIN" />                                
                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>                        
                        <intent-filter>
                                <action android:name="android.intent.action.SEND" />
                                <category android:name="android.intent.category.DEFAULT" />
                                <category android:name="android.intent.category.APP_BROWSER" />
                                <data android:mimeType="text/plain" /> 
                                <data android:mimeType="image/*" />
                        </intent-filter>
                        <intent-filter>
                            <action android:name="android.intent.action.SEND_MULTIPLE" />
                            <category android:name="android.intent.category.DEFAULT" />
                            <category android:name="android.intent.category.APP_BROWSER" />
                            <data android:mimeType="image/*" />
                        </intent-filter>
                                </activity>         <activity android:name="com.tns.ErrorReportActivity"/>  </application>

Then Add following lines of code in your app.js

application.android.on(application.AndroidApplication.activityResumedEvent, function (args) {
        console.log("Event: " + args.eventName + ", Activity: " + args.activity);
        var a = args.activity;
        try {
            var Intent_1 = android.content.Intent;
            var actionSend = Intent_1.ACTION_SEND;
            var actionSendMultiple = Intent_1.ACTION_SEND_MULTIPLE;
            var argIntent = a.getIntent();
            var argIntentAction = argIntent.getAction();
            var argIntentType = argIntent.getType();
            console.log(" ~~~~ Intent is ~~~~ :" + new String(argIntent.getAction()).valueOf());
            String.prototype.startsWith = function (str) {
                return this.substring(0, str.length) === str;
            };
            if (new String(argIntentAction).valueOf() === new String(Intent_1.ACTION_SEND).valueOf()) {
                if (new String(argIntentType).valueOf() === new String("text/plain").valueOf()) {
                    console.dump(cbParseTextAndUrl(argIntent));
                }
                else if (argIntentType.startsWith("image/")) {
                    console.log(cbParseImageUrl(argIntent));
                }
            }
            else if (new String(argIntentAction).valueOf() === new String(Intent_1.ACTION_SEND_MULTIPLE).valueOf()) {
                if (argIntentType.startsWith("image/")) {
                    var Uri = cbParseMultipleImageUrl(argIntent);
                    if (Uri !== null) {
                        var Uris = JSON.parse(Uri);
                        console.log(Uris);
                    }
                }
            }
            function cbParseTextAndUrl(argIntent) {
                var Patterns = android.util.Patterns;
                //let Matcher = java.util.regex.Matcher;
                var ListUrl = [];
                var text = argIntent.getStringExtra(Intent_1.EXTRA_TEXT);
                if (new String().valueOf() !== "null") {
                    var Matcher = Patterns.WEB_URL.matcher(text);
                    while (Matcher.find()) {
                        var url = Matcher.group();
                        ListUrl.push(url);
                    }
                    return { "text": text, "listUrl": ListUrl };
                }
            }
            function cbParseImageUrl(argIntent) {
                var imageUri = argIntent.getParcelableExtra(Intent_1.EXTRA_STREAM);
                if (imageUri != null) {
                    // Update UI to reflect image being shared
                    return imageUri;
                }
            }
            function cbParseMultipleImageUrl(argIntent) {
                var imageUris = argIntent.getParcelableArrayListExtra(Intent_1.EXTRA_STREAM);
                if (imageUris != null) {
                    // Update UI to reflect image being shared
                    return JSON.stringify(imageUris.toString());
                }
            }
        }
        catch (e) {
            console.log(e);
        }
    });

Now you can share your content from 3rd party app to your app.

Sihon answered 9/9, 2016 at 7:32 Comment(0)
W
1

As none of this answers are correct in 2023, with nativescript 7+ the way it works is

  1. add the intent filter like mentioned already:

         <intent-filter>
           <action android:name="android.intent.action.SEND" />
           <category android:name="android.intent.category.DEFAULT" />
           <data android:mimeType="image/*" />
         </intent-filter>
    
  2. listen to the activityNewIntentEvent. This is the only way to retrieve the incoming intent and extract the extra:

    if (isAndroid) {
      Application.android.on(AndroidApplication.activityNewIntentEvent, function (args: AndroidActivityNewIntentEventData) {
        console.log('Event : ' + args.intent);
      });
    }
Weigela answered 9/2, 2023 at 7:6 Comment(0)
N
0

In case if anyone is looking for most recent NS7 and NS8 compatible version, this works for me and for Android. This is tested on drawer template app from NS8. Javascript part is for home-page.js , just replace it's content with code below.

Imports are different for NS7 and NS8, which gets people confused.

Edit your AndroidManifest.xml

App_Resources/Android/src/main/AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="__PACKAGE__"
    android:versionCode="10000"
    android:versionName="1.0">

    <supports-screens
        android:smallScreens="true"
        android:normalScreens="true"
        android:largeScreens="true"
        android:xlargeScreens="true"/>

    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

    <application
        android:name="com.tns.NativeScriptApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme">

        <activity
            android:name="com.tns.NativeScriptActivity"
            android:label="@string/title_activity_kimera"
            android:configChanges="keyboard|keyboardHidden|orientation|screenSize|smallestScreenSize|screenLayout|locale|uiMode"
            android:theme="@style/LaunchScreenTheme">

            <meta-data android:name="SET_THEME_ON_LAUNCH" android:resource="@style/AppTheme" />

            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>

            <intent-filter>
                <action android:name="android.intent.action.SEND" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:mimeType="image/*" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.SEND" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:mimeType="text/plain" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.SEND_MULTIPLE" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:mimeType="image/*" />
            </intent-filter>
        </activity>
        <activity android:name="com.tns.ErrorReportActivity"/>
    </application>
</manifest>

Javascript

home/home-page.js

    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    const Observable = require("@nativescript/core").Observable;
    const application = require("@nativescript/core/application");

    import { Application } from '@nativescript/core'
    import { HomeViewModel } from './home-view-model'

    var vm = new Observable();

    export function onNavigatingTo(args) {
    const page = args.object
    page.bindingContext = new HomeViewModel();
    page.bindingContext = vm;
    vm.set("sharedText", "Waiting for intent...");
    if (application.android) {
        application.android.on(application.AndroidApplication.activityCreatedEvent, function (args) {
            var activity = args.activity;
            console.log(activity);
            vm.set("sharedText", "Intend data received");
            // Get intent, action and MIME type
            var intent = activity.getIntent();
            var action = intent.getAction();
            var type = intent.getType();
            if (android.content.Intent.ACTION_SEND === action && type != null) {
                if (type.startsWith("text/")) {
                    handleSendText(intent); // Handle text being sent
                }
                else if (type.startsWith("image/")) {
                    handleSendImage(intent); // Handle single image being sent
                }
            }
            else if (android.content.Intent.ACTION_SEND_MULTIPLE === action && type != null) {
                if (type.startsWith("image/")) {
                    handleSendMultipleImages(intent); // Handle multiple images being sent
                }
            }
            else {
                // Handle other intents, such as being started from the home screen
            }
        });
    }
    }

    function handleSendText(intent) {
    if (application.android) {
        var sharedText = intent.getStringExtra(android.content.Intent.EXTRA_TEXT);
        if (sharedText != null) {
            // Update UI to reflect text being shared
            console.log("sharedText: ", sharedText);
            console.log("Text received!");
            // set timeout - enough to update UI after app loading
            setTimeout(func, 1000);
            function func() {
                vm.set("sharedText", sharedText);
            }
        }
    }
    }
    function handleSendImage(intent) {
    if (application.android) {
        var imageUri = intent.getParcelableExtra(android.content.Intent.EXTRA_STREAM);
        if (imageUri != null) {
            // Update UI to reflect image being shared
            console.log("Image received!");
            var appContext = application.android.context;
            var bitmap = android.provider.MediaStore.Images.Media.getBitmap(appContext.getContentResolver(), imageUri);
            console.log("bitmap: ", bitmap);
            vm.set("bitmap", bitmap);
        }
    }
    }
    function handleSendMultipleImages(intent) {
    if (application.android) {
        var imageUris = intent.getParcelableArrayListExtra(android.content.Intent.EXTRA_STREAM);
        if (imageUris != null) {
            // Update UI to reflect multiple images being shared
            console.log("imageUris: ", imageUris);
            console.log("Multiple images received!");
        }
    }
    }

    export function onDrawerButtonTap(args) {
    const sideDrawer = Application.getRootView()
    sideDrawer.showDrawer()
    }
Nata answered 9/5, 2021 at 7:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.