Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ionic resource icon for Android push notifications #608

Open
schoettler opened this issue Oct 7, 2015 · 35 comments
Open

Ionic resource icon for Android push notifications #608

schoettler opened this issue Oct 7, 2015 · 35 comments

Comments

@schoettler
Copy link

Hey Ionic!

Would be nice if we could automatically set an icon for multiple resolutions as a custom push notification icon, as an addition to the app's icon & splash screen.

@elloboblanco
Copy link

Second! Just looking for a way to do this too.

@awebdeveloper
Copy link

+1

@ghost
Copy link

ghost commented Dec 4, 2015

I can't figure out a way to display an icon on my received push notifications.

@adyz
Copy link

adyz commented Dec 14, 2015

+1

I use phonegap-plugin-push plugin https://github.com/phonegap/phonegap-plugin-push for push notifications

I generate "old" icons with ionic resources command even if I don't use ionic in my project at all.

After that I generate a new png with a new name with this tool: http://romannurik.github.io/AndroidAssetStudio/icons-notification.html and paste all the generated folders in the platforms/android/res folder with the "merge" options. The notification icon must have a different name, not icon.png and when I init the push plugin I use the name of my new file here:

    "android": {
        senderID: vv.params.googleGCMProjectNumber,
        icon: "ic_stat_icon_material",
        iconColor: "grey"
    },

and the large icon from the JSON sent as push:

    "GCM": {
        title: "Large Icon", 
        message: "Loaded from drawables folder", 
        image: "icon"
    }

where icon is the name of the file generated by ionic.

Tested on two devices so far. Works fine.

@RafaelMCarvalho
Copy link

+1

5 similar comments
@igordeoliveirasa
Copy link

+1

@MazzMazz
Copy link

+1

@gauravarora
Copy link

+1

@ronycohen
Copy link

+1

@Samox
Copy link

Samox commented Feb 15, 2016

+1

@awebdeveloper
Copy link

Here is a solution

  1. Create a folder called push_icon in resources/android/
  2. Create the files in the format drawable-hopi-icon.png like you see in icon folder
  3. Create a after_prepare hook
#!/usr/bin/env node

var fs = require('fs');
var path = require('path');

var inputFolder = path.join(__dirname, '../../', 'resources/android/push_icon/');
var outputFolder = path.join(__dirname, '../../', '/platforms/android/res/');

console.log('------------------------------------------------------------------------------------------');
console.log("Running hook: "+path.basename(process.env.CORDOVA_HOOK));
console.log('------------------------------------------------------------------------------------------');

fs.readdir(inputFolder, function(err, list) {
    list.forEach(function(file){
        if (file.indexOf('drawable') === 0) {
            var destFolder = file.replace('-icon.png','');
            fs.createReadStream(inputFolder+file)
              .pipe(fs.createWriteStream(outputFolder + destFolder + '/notify.png'));
            console.log('# ' + file + ' --> ' + destFolder);
        }
    });

    console.log('-----------------------------------------------------------------------------------------');
});

@jakub-g
Copy link

jakub-g commented Feb 22, 2016

+1. please let us know if you consider the feature valuable, so maybe someone from community will send a PR for that

If you're unfamiliar with the context: in Android 5.0+, push notification icon has to be two-color: transparent background + white foreground; otherwise the default app icon is taken, and anything non-transparent is displayed as white (so very likely, the user will see a white square)

Now, to prevent that, you can have a separate icon only for push notifications, and pass that name to the cordova push plugin.

I'm for now using a combination of solutions from @adyz and @awebdeveloper i.e. generate icons via a website, commit them to git to a custom folder, then copy the images to platform/android/res in a hook.

@mainalikishan
Copy link

+1

3 similar comments
@alejandromagnorsky
Copy link

+1

@Remrem84
Copy link

+1

@pawurb
Copy link

pawurb commented Apr 8, 2016

+1

@wli
Copy link

wli commented Apr 14, 2016

For anyone here for ionic2, you can:

  1. Use this generator: http://romannurik.github.io/AndroidAssetStudio/icons-notification.html

  2. Put your icons in resources/android/ic_notification/. It should look like this:

    - resources/android/ic_notification/drawable-hdpi-v11/ic_notification.png
    - resources/android/ic_notification/drawable-hdpi/ic_notification.png
    - resources/android/ic_notification/drawable-mdpi-v11/ic_notification.png
    - resources/android/ic_notification/drawable-mdpi/ic_notification.png
    - resources/android/ic_notification/drawable-xhdpi-v11/ic_notification.png
    - resources/android/ic_notification/drawable-xhdpi/ic_notification.png
    - resources/android/ic_notification/drawable-xxhdpi-v11/ic_notification.png
    - resources/android/ic_notification/drawable-xxhdpi/ic_notification.png
    - resources/android/ic_notification/drawable-xxxhdpi-v11/ic_notification.png
    - resources/android/ic_notification/drawable-xxxhdpi/ic_notification.png
    
  3. stick this into gulpfile.js

    gulp.task('ic_notification', function() {
        gulp.src('./resources/android/ic_notification/**')
            .pipe(gulp.dest('./platforms/android/res'));
        });
    
  4. Add the 'ic_notification' task to the runSequence calls for 'build' and 'watch':

    gulp.task('watch', ['clean'], function(done){
      runSequence(
       ['sass', 'html', 'fonts', 'scripts', 'ic_notification'],
        function(){
          gulpWatch('app/**/*.scss', function(){ gulp.start('sass'); });
          gulpWatch('app/**/*.html', function(){ gulp.start('html'); });
          buildBrowserify({ watch: true }).on('end', done);
        }
      );
    });
    
    gulp.task('build', ['clean'], function(done){
      runSequence(
       ['sass', 'html', 'fonts', 'scripts', 'ic_notification'],
        function(){
          buildBrowserify().on('end', done);
        }
      );
    });
    

I think this whole process can be generalized and put into a plugin that should be included in https://github.com/driftyco/ionic-gulp-tasks.

@boyfunky
Copy link

boyfunky commented May 9, 2016

am i the only one experiencing this but all the icons generated via http://romannurik.github.io/AndroidAssetStudio/icons-notification.html are just all white circles. i dont see my icon at all. @wli

@wli
Copy link

wli commented May 9, 2016

@boyfunky notification icons are only two colors - white or transparent. The white circle implies that your icon has a circle shape. You probably want some kind of transparency so you get some kind of shape.

@shyamal890
Copy link

+1

1 similar comment
@saguilerao
Copy link

+1

@saguilerao
Copy link

Another way to prevent notification icon to be white-transparent is to set the Target SDK to any value below 20.. (lollipop)..

@pke
Copy link

pke commented Jun 19, 2016

Without hackery like lowering the target SDK just save the icon in 8bit Grayscale with Alpha-Channel.

@lucasbasquerotto
Copy link

lucasbasquerotto commented Dec 29, 2016

I created the hook below, based on this code, that you can set as an after prepare hook, without the need of external libraries:

#!/usr/bin/env node
var ROOT_DIR = process.argv[2];
var DIRS_TO_COPY = [{
	srcDir: "resources/other/android/res/",
	destDir: "platforms/android/res/"
}];

var fs = require('fs');
var path = require('path');

function copyFileSync(srcFile, target) {
	var destFile = target;

	//if target is a directory a new file with the same name will be created inside it
	if (fs.existsSync(target)) {
		if (fs.lstatSync(target).isDirectory()) {
			destFile = path.join(target, path.basename(srcFile));
		}
	}

	//console.log('copying ' + srcFile + ' to ' + destFile);
	fs.writeFileSync(destFile, fs.readFileSync(srcFile));
}

function copyFolderRecursiveSync(sourceFolder, targetFolder) {
	var files = null;

	if (!fs.existsSync(targetFolder)) {
		fs.mkdirSync(targetFolder);
	}

	//copy
	if (fs.lstatSync(sourceFolder).isDirectory()) {
		files = fs.readdirSync(sourceFolder) || [];

		files.forEach(function (curSource) {
			var curSourceFull = path.join(sourceFolder, curSource);

			if (fs.lstatSync(curSourceFull).isDirectory()) {
				var curTargetFolder = path.join(targetFolder, path.basename(curSource));
				copyFolderRecursiveSync(curSourceFull, curTargetFolder);
			} else {
				copyFileSync(curSourceFull, targetFolder);
			}
		});
	}
}

DIRS_TO_COPY.forEach(function (dirInfo) {
	var srcDirFull = path.join(ROOT_DIR, dirInfo.srcDir);
	var destDirFull = path.join(ROOT_DIR, dirInfo.destDir);
	copyFolderRecursiveSync(srcDirFull, destDirFull);
});

Just create a .js file with the above code called, for instance, my_hook.js, and put it inside the [YOUR_PROJECT]/hooks/after_prepare/ folder (it works just like that with Ionic2). I don't know if Ionic1 or a non-ionic cordova project will run the hook automatically, but you can add it to the config.xml in these cases:

<hook type="after_prepare" src="hooks/after_prepare/my_hook.js" />

The hook copies all files and directories recursively inside resources/other/android/res/ (I created this folder, where I put all drawables I use, except the app icon and splash screen that are already generated by Ionic) into platforms/android/res/ (where all drawables are put in android). I don't need to specify each file to be copied, because it will copy the entire folder.

Just make sure that the icons are in the correct directories. The utility below already does that for you (it creates a zip file with the correct folders, just paste it inside resources/other/android/res/). You can add another directory for iOS too (in the DIRS_TO_COPY array).

You can create a notification icon for android in https://romannurik.github.io/AndroidAssetStudio/icons-generic.html.

@lincolnthree
Copy link

Don't forget that once you add these icons to the res/ folder, you need to configure the push plugin to use them:

E.g. If you have res/other/android/res/:

./drawable-hdpi/ic_notify.png
./drawable-mdpi/ic_notify.png
./drawable-xhdpi/ic_notify.png
./drawable-xxhdpi/ic_notify.png
./drawable-xxxhdpi/ic_notify.png

You'd still need need:

const cloudSettings: CloudSettings = {
	'core': {
		'app_id': '...'
	},
	'push': {
		'sender_id': '...',
		'pluginConfig': {
			'ios': {
				'badge': true,
				'sound': true,
			},
			'android': {
				'iconColor': '#343434',
				'icon': 'ic_notify', <--- this is required to specify which icon to use - otherwise it will be blank.
			}
		}
	}
};

@shyamal890
Copy link

+1

@sbozzie
Copy link

sbozzie commented Mar 14, 2017

Hi Guys,

I'm having some issues, and can't seem to get the combination of images/folders and config right here to get the small icon working in the notification bar of Android - I'm simply shown a square,

In my app.js I have:

$ionicCloudProvider.init({
   "core": {
     "app_id": "APPIDHERE"
   },
    "push": {
      "sender_id": "SENDERIDHERE",
      "pluginConfig": {
        "ios": {
          "badge": true,
          "sound": true
        },
        "android": {
            "iconColor": "#00AEED",
            "icon":"ic_notify"
        }
      }
    }
 });`

I can see that this config is being used, by changing "iconColor" I am able to get a little blue or red square!

Within my \android\res\drawable-resolution folders, I have the png's as generated by the AndroidAssetStudio generator tool, as white on alpha png's

image

What am I missing?

@lincolnthree
Copy link

The folders containing the icon files need to end up here:

platforms/android/res/

Make sure your build is putting them there. I use this 'after_prepare' hook script:

#!/usr/bin/env node

var ROOT_DIR = process.argv[2];
var DIRS_TO_COPY = [{
	srcDir: "resources/other/android/res/",
	destDir: "platforms/android/res/"
}];

var fs = require('fs');
var path = require('path');

function copyFileSync(srcFile, target) {
	var destFile = target;

	//if target is a directory a new file with the same name will be created inside it
	if (fs.existsSync(target)) {
		if (fs.lstatSync(target).isDirectory()) {
			destFile = path.join(target, path.basename(srcFile));
		}
	}

	//console.log('copying ' + srcFile + ' to ' + destFile);
	fs.writeFileSync(destFile, fs.readFileSync(srcFile));
}

function copyFolderRecursiveSync(sourceFolder, targetFolder) {
	var files = null;

	if (!fs.existsSync(targetFolder)) {
		fs.mkdirSync(targetFolder);
	}

	//copy
	if (fs.lstatSync(sourceFolder).isDirectory()) {
		files = fs.readdirSync(sourceFolder) || [];

		files.forEach(function(curSource) {
			var curSourceFull = path.join(sourceFolder, curSource);

			if (fs.lstatSync(curSourceFull).isDirectory()) {
				var curTargetFolder = path.join(targetFolder, path.basename(curSource));
				copyFolderRecursiveSync(curSourceFull, curTargetFolder);
			} else {
				copyFileSync(curSourceFull, targetFolder);
			}
		});
	}
}

DIRS_TO_COPY.forEach(function(dirInfo) {
	var srcDirFull = path.join(ROOT_DIR, dirInfo.srcDir);
	var destDirFull = path.join(ROOT_DIR, dirInfo.destDir);
	copyFolderRecursiveSync(srcDirFull, destDirFull);
});

@lincolnthree
Copy link

It's a real pain to get right. And the error messaging is non-existent. Lots of trial and error.

@sbozzie
Copy link

sbozzie commented Mar 14, 2017

Is just manually putting them into location not enough? Would a Gulp task do the job?

@Jharilela
Copy link

I think that the hook file does a good job in copying the files after execution but i think the real problem lies in the android firmware unable to detect the location of the icon from its root

hutingung added a commit to fourmisolutions/epaper that referenced this issue Mar 20, 2017
@dovk
Copy link

dovk commented Sep 16, 2017

If your only problem is with the notifications icons appearing correctly on Android, the following worked for me - take the drawable-xhdpi-icon icon (size 96x96), rename it icon.png and place it in two places:

   /src/assets/img
   /platforms/android/res/drawable

The drawable folder is a new folder which can be created by copying platforms/android/res/mipmap-xhdpi to platforms/android/res/drawable manually or with the aid of a hook. In your code, the local or geofence notification is referenced as follows:

      smallIcon: 'res://icon',
      icon: 'file://assets/img/icon.png'

If ionic cordova resources is part of the problem, you can do your own one-time setup by taking your largest icon and, with the help of a resizing tool such as resizeimage.net, create a set of icons for iOS and Android.

The Excel here https://github.com/dovk/howto_resources-folder has a list of the sizes and names of the .png files to create. You then place them in their respective resources folder just like ionic cordova resources would have done - for example in resources/android/icon, resources/ios/splash and so on.

If you do so, then ionic cordova platform add android or ionic cordova platform add ios should not be used anymore, as this also does ionic cordova resources - What you need to do is cordova platform add ... --save (without the ionic in the beginning).

image
image
image

@marcojr
Copy link

marcojr commented Sep 19, 2017

I can't make this work...My recipe...

  1. used https://romannurik.github.io/AndroidAssetStudio/icons-generic.html to generate the icons
  2. Placed the icons in this way...(ic_notify, in white)

captura de tela 2017-09-19 as 12 22 40

  1. Created android_icons at hooks/after_prepare

  2. Added on the config.xml after the

  3. Executed ionic cordova run android

  4. got an error: Running command: _/Users/marcojr/Projects/munkat/app/hooks/after_prepare/android_icons.js
    /Users/marcojr/Projects/munkat/app
    fs.js:994
    binding.lstat(pathModule._makeLong(path), statValues);
    ^

     Error: ENOENT: no such file or directory, lstat 
     '/Users/marcojr/Projects/munkat/app/resources/other/android/res/'_
    
  5. Changed line 5 of the hook file from srcDir: "resources/other/android/res/" to srcDir: "resources/android/"

  6. Executed ionic cordova run android

  7. Got another error : Error: ENOENT: no such file or directory, mkdir 'run/platforms/android/res/'

  8. Dropped the hook from the config.xml, got another error: /Users/marcojr/Projects/munkat/app/platforms/android/res/icon/drawable-hdpi-ic_notify.png:1:1: Error: O conteúdo não é permitido no prólogo. (The content is not allowed on prologue)

  9. Decided to try awebdeveloper's solution. Got an error: Error: Path must be a string. Received undefined

any suggestions ?

@lucasbasquerotto
Copy link

lucasbasquerotto commented Sep 19, 2017

@marcojr I recommend you not rename the files generated at https://romannurik.github.io/AndroidAssetStudio/icons-generic.html , but keep them with the same name and inside the created folders. What should be done is copying all the folders inside srcDir to destDir.

I defined srcDir as resources/other/android/res/ instead of resources/android/res/ because ionic creates the icon and splashscreen inside resources/android/ and that might (possibly) cause some conflicts, or erase the contents inside this folder. You could use another folder instead of resources/other/, but I recommend not to use resources/android/ (I'm not certain, but your last error may be because of this).

Like I said before, the contents inside srcDir should be folders with icons, the folders names should be like drawable-hdpi, drawable-mdpi, and so on... The notification icon should have the same name across the folders (like ic_notif.png, the same name for all icons, the utility in the link above (to create the icons) already does all that, creating the folders with the correct name and the icons, you just need to copy and paste it inside your srcDir). Look at the location of my icons, their names and the folder names:

icons

My notification icon is ic_99.png, the other icons are for other reasons.

The hook just copy the contents inside srcDir to destDir, so it create those folders inside platforms/android/res/:

icons2

First I'd recommend to use the same paths as mine to see if it works (if it works you can move your folders to another loaction and change the srcDir path accordingly).

The only error you got that I don't know why is that with mkdir 'run/platforms/android/res/', it should be mkdir 'platforms/android/res/', I've never got this error, don't know why this happened.

I don't recommend putting the icons manually inside the platforms folder, because the hook is basically to avoid that (the platforms folder should be such that you could delete it and generate it again without doing any manual changes).

@marcojr
Copy link

marcojr commented Sep 19, 2017

Ty, guys ! But looks like the solution provided by dovk really works and it's insanely simple !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests