Categories
discuss

Targeting S+ (version 31 and above) requires that one of FLAG_IMMUTABLE or FLAG_MUTABLE be specified when creating a PendingIntent, On AlarmPingSender

Problem

Targeting S+ (version 31 and above) requires that one of FLAG_IMMUTABLE or FLAG_MUTABLE be specified when creating a PendingIntent. I got it after updating target SDK to 31. the error always come after AlarmPingSender. But i dont know any class that used AlarmPingSender.

2021-10-31 10:43:04.990 17031-17341/com.app.mobile D/AlarmPingSender: Register alarmreceiver to MqttServiceMqttService.pingSender.com.app.mobile-2e24ccbde048f2e91635651784
2021-10-31 10:43:04.993 17031-17341/com.app.mobile E/AndroidRuntime: FATAL EXCEPTION: MQTT Rec: com.app.mobile-2e24ccbde048f2e91635651784
    Process: com.app.mobile, PID: 17031
    java.lang.IllegalArgumentException: com.app.mobile: Targeting S+ (version 31 and above) requires that one of FLAG_IMMUTABLE or FLAG_MUTABLE be specified when creating a PendingIntent.
    Strongly consider using FLAG_IMMUTABLE, only use FLAG_MUTABLE if some functionality depends on the PendingIntent being mutable, e.g. if it needs to be used with inline replies or bubbles.
        at android.app.PendingIntent.checkFlags(PendingIntent.java:375)
        at android.app.PendingIntent.getBroadcastAsUser(PendingIntent.java:645)
        at android.app.PendingIntent.getBroadcast(PendingIntent.java:632)
        at org.eclipse.paho.android.service.AlarmPingSender.start(AlarmPingSender.java:76)
        at org.eclipse.paho.client.mqttv3.internal.ClientState.connected(ClientState.java:1150)
        at org.eclipse.paho.client.mqttv3.internal.ClientState.notifyReceivedAck(ClientState.java:987)
        at org.eclipse.paho.client.mqttv3.internal.CommsReceiver.run(CommsReceiver.java:118)
        at java.lang.Thread.run(Thread.java:920)

What I Already done

  • Upgrade WorkManager to 2.7.0
  • set AllProject to force use WorkManager to 2.7.0
  • change all existing PendingIntent to use FLAG_IMMUTABLE
  • there’s old code that still use gcm and disable it
  • Updating all Firebase package (some said its because of later version of analytics)

Library Used

  • OneSignal
  • Qiscus
  • Firebase
  • WorkManager

Answer

After several attempt to fix this, i gave up and try to contact Qiscus. And they release new version that handle this Pending Intent behaviour change. So if anyone use Qiscus and got this error, you can use latest tag

https://github.com/qiscus/qiscus-sdk-android/releases/tag/1.3.35

Categories
discuss

NestJS – Expected undefined to be a GraphQL schema

I am trying to setup a very small GraphQL API using NestJS 8. I installed all required redepndencies from the documentation, but when I start the server, I get this error:

[Nest] 22727  - 10/30/2021, 10:11:10 AM     LOG [NestFactory] Starting Nest application...
[Nest] 22727  - 10/30/2021, 10:11:10 AM     LOG [InstanceLoader] AppModule dependencies initialized +43ms
[Nest] 22727  - 10/30/2021, 10:11:10 AM     LOG [InstanceLoader] TypeOrmModule dependencies initialized +0ms
[Nest] 22727  - 10/30/2021, 10:11:10 AM     LOG [InstanceLoader] ConfigHostModule dependencies initialized +7ms
[Nest] 22727  - 10/30/2021, 10:11:10 AM     LOG [InstanceLoader] ConfigModule dependencies initialized +1ms
[Nest] 22727  - 10/30/2021, 10:11:10 AM     LOG [InstanceLoader] ConfigModule dependencies initialized +1ms
[Nest] 22727  - 10/30/2021, 10:11:11 AM     LOG [InstanceLoader] GraphQLSchemaBuilderModule dependencies initialized +21ms
[Nest] 22727  - 10/30/2021, 10:11:11 AM     LOG [InstanceLoader] GraphQLModule dependencies initialized +1ms
[Nest] 22727  - 10/30/2021, 10:11:11 AM     LOG [InstanceLoader] TypeOrmCoreModule dependencies initialized +93ms
[Nest] 22727  - 10/30/2021, 10:11:11 AM     LOG [InstanceLoader] TypeOrmModule dependencies initialized +0ms
[Nest] 22727  - 10/30/2021, 10:11:11 AM     LOG [InstanceLoader] PostModule dependencies initialized +0ms

/workspace/node_modules/graphql/type/schema.js:35
    throw new Error(
          ^
Error: Expected undefined to be a GraphQL schema.
    at assertSchema (/workspace/node_modules/graphql/type/schema.js:35:11)
    at validateSchema (/workspace/node_modules/graphql/type/validate.js:34:28)
    at graphqlImpl (/workspace/node_modules/graphql/graphql.js:52:64)
    at /workspace/node_modules/graphql/graphql.js:21:43
    at new Promise (<anonymous>)
    at graphql (/workspace/node_modules/graphql/graphql.js:21:10)
    at GraphQLSchemaFactory.create (/workspace/node_modules/@nestjs/graphql/dist/schema-builder/graphql-schema.factory.js:48:60)
    at GraphQLSchemaBuilder.buildSchema (/workspace/node_modules/@nestjs/graphql/dist/graphql-schema.builder.js:62:52)
    at GraphQLSchemaBuilder.build (/workspace/node_modules/@nestjs/graphql/dist/graphql-schema.builder.js:24:31)
    at GraphQLFactory.mergeOptions (/workspace/node_modules/@nestjs/graphql/dist/graphql.factory.js:33:69)

I don’t understand this error, as I am just following the documentation…

// app.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { GraphQLModule } from '@nestjs/graphql';
import { TypeOrmModule } from '@nestjs/typeorm';
import { GraphqlOptions } from './config/graphql.config';
import { typeOrmConfigAsync } from './config/typeorm.config';
import { PostModule } from './post/post.module';

@Module({
  imports: [
    ConfigModule.forRoot({ isGlobal: true }),
    TypeOrmModule.forRootAsync(typeOrmConfigAsync),
    GraphQLModule.forRootAsync({
      useClass: GraphqlOptions,
    }),
    PostModule,
  ],
})
export class AppModule {}
// graphql.config.ts
import { Injectable } from '@nestjs/common';
import { GqlModuleOptions, GqlOptionsFactory } from '@nestjs/graphql';

@Injectable()
export class GraphqlOptions implements GqlOptionsFactory {
  createGqlOptions(): Promise<GqlModuleOptions> | GqlModuleOptions {
    return {
      autoSchemaFile: 'schema.gql',
      sortSchema: true,
      debug: true,
      installSubscriptionHandlers: true,
      context: ({ req }) => ({ req }),
    };
  }
}
// post.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Post } from './post.entity';
import { PostResolver } from './post.resolver';
import { PostService } from './post.service';

@Module({
  imports: [TypeOrmModule.forFeature([Post])],
  providers: [PostService, PostResolver],
  exports: [PostService],
})
export class PostModule {}
// post.entity.ts
import { Field, ID, ObjectType } from '@nestjs/graphql';
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';

@Entity('post')
@ObjectType()
export class Post {
  @Field(() => ID)
  @PrimaryGeneratedColumn('uuid')
  id: string;

  @Field()
  @Column({ nullable: false })
  title: string;

  @Field()
  @Column({ nullable: false, unique: true })
  slug: string;

  @Field()
  @Column({ nullable: false })
  content: string;

  @Field()
  @Column({ type: 'timestamp' })
  createdAt: Date;

  @Field()
  @Column({ type: 'timestamp', nullable: true })
  updatedAt: Date;
}

Does anyone can highlight what’s wrong with my project?

Answer

I was receiving the same errors. After debugging step by step, the answer is that @nestjs/graphql@9.1.1 is not compatible with GraphQL@16.

Specifically, GraphQL@16 changed the gqaphql function, as called from within graphqlImpl, to only support args without a schema:

function graphql(argsOrSchema, source, rootValue, contextValue, variableValues, operationName, fieldResolver, typeResolver) {
  var _arguments = arguments;

  /* eslint-enable no-redeclare */
  // Always return a Promise for a consistent API.
  return new Promise(function (resolve) {
    return resolve( // Extract arguments from object args if provided.
    _arguments.length === 1 ? graphqlImpl(argsOrSchema) : graphqlImpl({
      schema: argsOrSchema,
      source: source,
      rootValue: rootValue,
      contextValue: contextValue,
      variableValues: variableValues,
      operationName: operationName,
      fieldResolver: fieldResolver,
      typeResolver: typeResolver
    }));
  });
}

To resolve, you will need to downgrade your graphql version to 15.x.

Categories
discuss

Why checkout step not recorded in the Google Analytics report?

I’m making an enhanched ecommerce tracking with google analytics. I’m following the existing implementation in gtag.js. I have 4 checkout steps including shipping method data, payment method data, pending payment, and also paid (purchase). I’ve made the codes for each step below:

1. Shipping Method

<script>
    gtag('event', 'set_checkout_option', {
        "checkout_step": 1,
        "checkout_option": "shipping method",
        "value": ""
    });
</script>

2. Payment Method

<script>
    gtag('event', 'set_checkout_option', {
        "checkout_step": 2,
        "checkout_option": "payment method",
        "value": ""
    });
</script>

3. Pending Payment

$("#order-now-action").on('click', function() {
    gtag('event', 'set_checkout_option', {
        "checkout_step": 3,
        "checkout_option": "pending",
        "id": ""
    });
})

This is the checkout funnel that I created in Ecommerce Settings. enter image description here

And this is a report in the checkout behavior menu. The shipping method is recorded, but why in step 2 (payment method) to step 4 (purchase) is it not recorded? enter image description here

even though, in the sales performance menu, the transaction is recorded? enter image description here

for steps 1-3 is in 1 page, while the purchase (step 4) I did on the backend using a single url. Is it because it’s on 1 page so it’s not recorded?

Answer

I’m very confused in solving this problem but I found the right answer why my checkout step is not recorded. This happened because set_checkout_option could not be used multiple times in one page, so I replaced it with the checkout_progress event. Because as in this Measure checkout steps documentation, To measure each subsequent checkout step, send a checkout_progress. I also modified my code a bit to be like this:

1.Shipping Method

<script>
    function checkoutProgressShippingMethodGA() {
        gtag('event', 'checkout_progress', {
            "checkout_step": 1,
            "checkout_option": "Shipping Method",
            "value": ""
        });
    }
    checkoutProgressShippingMethodGA();
</script>

2.Payment Method

<script>
    function checkoutProgressPaymentMethodGA() {
        gtag('event', 'checkout_progress', {
            "checkout_step": 2,
            "checkout_option": "Payment Method",
            "value": ""
        });
    }
    checkoutProgressPaymentMethodGA();
</script>

and tadaaaa… my checkout step has been recorded (**purchase has not been recorded because I have not implemented it on the backend) enter image description here

Categories
discuss

Android 12: How to prevent activity restart on changing phone wallpaper?

On Android 12,

  1. If we open an activity

  2. Go to the home screen of the phone to change the wallpaper

  3. Switch back to our activity, the activity restarts.

It seems it is related to the Material You theming.

I would like to disable the restarting of activity when my app comes to the foreground. Is there a way?

Answer

It is a non-traditional configuration change. By “non-traditional”, I mean that it cannot be blocked by android:configChanges — your activity will be destroyed and recreated whether you like it or not.

If you have Configuration objects from before and after the change, you can determine that this scenario occurred by calling diff() on the newer Configuration to compare it to the older one:

val diff = resources.configuration.diff(vm.originalConfiguration)

Log.d("WallpaperCCTest", "matches CONFIG_ASSETS_PATHS? ${(diff.toLong() and 0x80000000) != 0L}")

Here, vm.originalConfiguration points to the older Configuration, and we get the current Configuration from the Resources object. (diff.toLong() and 0x80000000) != 0L will evaluate to true if a wallpaper change or something similar triggered the configuration change. There are other edge cases for this — this whole “unblockable configuration change” thing came about when Sony got Google to add support for runtime resource overlays (RROs) back in 2017. So, some of those “change the system theme” apps might trigger this same unblockable configuration change.

As Nguyễn Hoài Nam notes, you can detect this from onConfigurationChanged() of a custom Application. Or, have your viewmodel hold onto the previous Configuration and compare it with the current one in onCreate() of your activity.

I have more on this issue in this blog post. AFAIK, there is no way to opt out of this configuration change, so if your app was designed to avoid configuration changes, you may be out of luck.

Categories
discuss

Date-fns format distance is not in correct words

I am facing a problem with the UI and want to show the timestamp distance into 3 hours ago and 4 hours ago etc. The timestamp coming from the server with a property named createdAt which has the following value.

createdAt: "2021-10-27T05:24:37.642Z"

To solve this problem I am using library like date-fns v2.25.0 builtin function formatDistance.

import { formatDistance} from 'date-fns';

const timestamp = createdAt ? new Date(createdAt) : '';
console.log(formatDistance(Date.now(), timestamp, {addSuffix: true}));
    

But it is giving back the distance in the following words

in about 3 hours
in about 4 hours

instead of

3 hours ago
4 hours ago

What I am doing wrong? If you know any other good library please you can share.

Answer

Reverse the arguments:

console.log(formatDistance(timestamp, Date.now(), {addSuffix: true}));
Source: stackoverflow
Text is available under the Creative Commons Attribution-ShareAlike License; additional terms may apply. By using this site, you agree to the Privacy Policy, and Copyright Policy. Content is available under CC BY-SA 3.0 unless otherwise noted. The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 © No Copyrights, All Questions are retrived from public domain..