Giter Club home page Giter Club logo

whatsapp_bot_flutter's Introduction

Whatsapp bot flutter

whatsapp_bot_flutter_logo

whatsapp_bot_flutter version

whatsapp_bot_flutter_mobile version

whatsapp_bot_flutter_web version

Getting Started

We can use this library in Flutter as well as Pure dart projects , checkout dart_example

First launch on Desktop apps will take some time, it will download chromium files locally, using puppeteer

Usage

Get WhatsappClient using connect method

// use WhatsappBotFlutterMobile.connect for Android/IOS platforms
WhatsappClient? whatsappClient = await WhatsappBotFlutter.connect(
  onConnectionEvent: (ConnectionEvent event) {
    print(event.toString());
  },
  onQrCode: (String qr, Uint8List? imageBytes) {
    // use imageBytes to display in flutter : Image.memory(imageBytes)
    print(WhatsappBotFlutter.convertStringToQrCode(qr));
  },
);

We have these modules to access whatsappClient features :

WhatsappClient.chat
WhatsappClient.contact
WhatsappClient.profile
WhatsappClient.group

Use sendTextMessage to send a text message

phone parameter can be of this format : countryCode+phoneNumber , eg : 91xxxxxxxxxx , or we can get phone from messageEvents in this format : countryCode+phone+"@c.us"

await whatsappClient.chat.sendTextMessage(
    phone: "------",
    message: "Test Message",
);

Use sendFileMessage to send a File

await whatsappClient.chat.sendFileMessage(
    phone: "------",
    fileBytes: fileBytes, // Pass file bytes
    caption: "Test Message", // Optional
    fileType: fileType, // document, image, audio
);

To get whatsapp connection Events , subscribe to whatsappClient.connectionEventStream

whatsappClient.connectionEventStream.listen((event) {
  // Connection Events : authenticated,logout,connected.....
});

To get new Messages

whatsappClient.on(WhatsappEvent.chat_new_message, (data) {
    List<Message> messages = Message.parse(data);
    // replyMessageId  is optional , add this to send a reply message
    whatsappClient.chat.sendTextMessage(
      phone: message.from,
      message: "Hey !",
      replyMessageId: message.id,
    );
});

We can listen to multiple events like this

whatsappClient.on(WhatsappEvent.EVENT_NAME, (data) {})

To stop listening to an event

whatsappClient.off(WhatsappEvent.EVENT_NAME);

Features

Supported Whatsapp features : - Create multiple whatsapp clients
  • Login with QR
  • Auto refresh QrCode
  • Logout
  • Keep session
  • Listen to whatsapp events
  • Reject calls
  • Send text message
  • Send image, audio & document
  • Send location message
  • Send poll in groups
  • Send contact card
  • Reply to a message
  • Archive/Unarchive chats
  • Mute/Unmute chat
  • Clear chat
  • Delete chat
  • Get lastSeen
  • Get chats
  • Mark messages as seen
  • Mark message as unread
  • Pin/Unpin chat
  • Delete messages
  • Download media
  • Get messages
  • Get profile picture
  • Get status
  • Get contacts
  • Get status of loggedIn user
  • Set status
  • check if logged in user have business account
  • Set profile picture of logged in user
  • and many more..

Mobile Setup (Android/IOS)

To setup on Android , make sure to checkout flutter_inappwebview documentation for Android and IOS setup Android sdk:minSdkVersion cannot be smaller than version 19

Desktop setup (Windows/Mac/Linux)

For Macos , Enable outgoing and incoming connections, If getting sandbox issue , try disabling sandbox mode comment this out in macos/Runner/*.entitlements:

<key>com.apple.security.app-sandbox</key>
<true/>

Should run out of the box in Windows and Linux

Web setup

checkout web demo app : https://rohitsangwan01.github.io/whatsapp_bot_flutter

To run natively on Web, checkout whatsapp_bot_flutter_web

We can use browserless, Create a free account there and get API_TOKEN from browserless, and use this url to connect : wss://chrome.browserless.io?token=API_TOKEN

Or we can run puppeteer, and get browserWsEndpoint from there and pass into the connect method, checkout this example

then pass this browserWsEndpoint in connect method, and also requires wppJsContent, we can download this file from here, add this file in assets and pass like this,

await WhatsappBotFlutter.connect(
    browserWsEndpoint: "BROWSER_WS_ENDPOINT_URL",
    wppJsContent: await rootBundle.loadString("assets/wpp.js"),
);

We can use this on Mobile or Desktop platforms as well , to connect to a chrome server hosted somewhere else

If we have to access this webSocket url locally on Mobile or other platforms , we can use ngrok to expose our local Websocket url to internet

Resources

Thanks to wa-js for exporting functions from WhatsApp Web

Disclaimer

This project is not affiliated, associated, authorized, endorsed by, or in any way officially connected with WhatsApp or any of its subsidiaries or its affiliates. The official WhatsApp website can be found at https://whatsapp.com. "WhatsApp" as well as related names, marks, emblems and images are registered trademarks of their respective owners.

Note

Its just initial version, I can't guarantee you will not be blocked by using this method, try to avoid primary whatsapp numbers. WhatsApp does not allow bots or unofficial clients on their platform, so this shouldn't be considered totally safe.

whatsapp_bot_flutter's People

Contributors

issacwilliandev avatar rohitsangwan01 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

whatsapp_bot_flutter's Issues

[New feature] Send & Remove message reaction

Hey Rohit,

Tested ✅ It is working fine.

Add in wpp_chat.dart:

  /// Emoji list: https://unicode.org/emoji/charts/full-emoji-list.html
  /// To remove reaction, set [emoji] to null
  Future sendReactionToMessage({
    required MessageId messageId,
    String? emoji,
  }) async {
    String? serialized = messageId.serialized;
    return await wpClient.evaluateJs(
      '''WPP.chat.sendReactionToMessage(${serialized.jsParse}, ${emoji != null ? emoji.jsParse : false});''',
      methodName: "sendReactionToMessage",
    );
  }

Deploy docker to Google Cloud Run

Hey there,

Did someone successfully deployed via docker to Google Cloud Run?

In the logs I always stay stuck at:

ConnectionEvent.downloadingChrome

HandshakeException error when trying to connect

I get the following error when try to initialize WhatsappClient on windows:
flutter: HandshakeException: Handshake error in client (OS Error:
SSLV3_ALERT_HANDSHAKE_FAILURE(../../third_party/boringssl/src/ssl/tls_record.cc:594)
HANDSHAKE_FAILURE_ON_CLIENT_HELLO(../../third_party/boringssl/src/ssl/handshake.cc:644))

Sending video as attachment

Hello thanks for great work

but how to send video as attachment

there is only document, image, audio , unknown

[New feature] Forward Message or Image with caption

Hey Rohit,

Tested ✅ It is working fine.

Add in wpp_chat.dart:

  /// [forwardTextMessage] may throw errors if passed an invalid contact
  /// or if this method completed without any issue , then probably message sent successfully
  Future forwardTextMessage({
    required String phone,
    required MessageId messageId,
    bool displayCaptionText = false,
    bool multicast = false,
  }) async {
    String? serialized = messageId.serialized;
    return await wpClient.evaluateJs('''WPP.chat.forwardMessage(${phone.phoneParse}, ${serialized.jsParse}, {
            displayCaptionText: $displayCaptionText,
            multicast: $multicast,
          });''', methodName: "forwardMessage");
  }

Add captiontoMessage model:

class Message {
  Message({
    required this.id,
    required this.body,
    required this.type,
    required this.t,
    required this.notifyName,
    required this.from,
    required this.to,
    required this.self,
    required this.isNewMsg,
    required this.star,
    required this.kicNotified,
    required this.recvFresh,
    required this.isFromTemplate,
    required this.pollInvalidated,
    required this.broadcast,
    required this.isForwarded,
    required this.hasReaction,
    required this.ephemeralOutOfSync,
    required this.productHeaderImageRejected,
    required this.lastPlaybackProgress,
    required this.isDynamicReplyButtonsMsg,
    required this.isMdHistoryMsg,
    required this.stickerSentTs,
    required this.requiresDirectConnection,
    required this.pttForwardedFeaturesEnabled,
    required this.caption,
  });

  final MessageId? id;
  final String body;
  final String type;
  final int t;
  final String notifyName;
  final String from;
  final String to;
  final String self;
  final bool isNewMsg;
  final bool star;
  final bool kicNotified;
  final bool recvFresh;
  final bool isFromTemplate;
  final bool pollInvalidated;
  final bool broadcast;
  final bool isForwarded;
  final bool hasReaction;
  final bool ephemeralOutOfSync;
  final bool productHeaderImageRejected;
  final int lastPlaybackProgress;
  final bool isDynamicReplyButtonsMsg;
  final bool isMdHistoryMsg;
  final int stickerSentTs;
  final bool requiresDirectConnection;
  final bool pttForwardedFeaturesEnabled;
  final String caption;

  Message copyWith({
    MessageId? id,
    String? body,
    String? type,
    int? t,
    String? notifyName,
    String? from,
    String? to,
    String? self,
    int? ack,
    bool? isNewMsg,
    bool? star,
    bool? kicNotified,
    bool? recvFresh,
    bool? isFromTemplate,
    bool? pollInvalidated,
    bool? broadcast,
    bool? isForwarded,
    bool? hasReaction,
    bool? ephemeralOutOfSync,
    bool? productHeaderImageRejected,
    int? lastPlaybackProgress,
    bool? isDynamicReplyButtonsMsg,
    bool? isMdHistoryMsg,
    int? stickerSentTs,
    bool? requiresDirectConnection,
    bool? pttForwardedFeaturesEnabled,
    String? caption,
  }) {
    return Message(
      id: id ?? this.id,
      body: body ?? this.body,
      type: type ?? this.type,
      t: t ?? this.t,
      notifyName: notifyName ?? this.notifyName,
      from: from ?? this.from,
      to: to ?? this.to,
      self: self ?? this.self,
      isNewMsg: isNewMsg ?? this.isNewMsg,
      star: star ?? this.star,
      kicNotified: kicNotified ?? this.kicNotified,
      recvFresh: recvFresh ?? this.recvFresh,
      isFromTemplate: isFromTemplate ?? this.isFromTemplate,
      pollInvalidated: pollInvalidated ?? this.pollInvalidated,
      broadcast: broadcast ?? this.broadcast,
      isForwarded: isForwarded ?? this.isForwarded,
      hasReaction: hasReaction ?? this.hasReaction,
      ephemeralOutOfSync: ephemeralOutOfSync ?? this.ephemeralOutOfSync,
      productHeaderImageRejected: productHeaderImageRejected ?? this.productHeaderImageRejected,
      lastPlaybackProgress: lastPlaybackProgress ?? this.lastPlaybackProgress,
      isDynamicReplyButtonsMsg: isDynamicReplyButtonsMsg ?? this.isDynamicReplyButtonsMsg,
      isMdHistoryMsg: isMdHistoryMsg ?? this.isMdHistoryMsg,
      stickerSentTs: stickerSentTs ?? this.stickerSentTs,
      requiresDirectConnection: requiresDirectConnection ?? this.requiresDirectConnection,
      pttForwardedFeaturesEnabled: pttForwardedFeaturesEnabled ?? this.pttForwardedFeaturesEnabled,
      caption: caption ?? this.caption,
    );
  }

  factory Message.fromJson(Map<String, dynamic> json) {
    return Message(
      id: json["id"] == null ? null : MessageId.fromJson(json["id"]),
      body: json["body"] ?? "",
      type: json["type"] ?? "",
      t: json["t"] ?? 0,
      notifyName: json["notifyName"] ?? "",
      from: json["from"] ?? "",
      to: json["to"] ?? "",
      self: json["self"] ?? "",
      isNewMsg: json["isNewMsg"] ?? false,
      star: json["star"] ?? false,
      kicNotified: json["kicNotified"] ?? false,
      recvFresh: json["recvFresh"] ?? false,
      isFromTemplate: json["isFromTemplate"] ?? false,
      pollInvalidated: json["pollInvalidated"] ?? false,
      broadcast: json["broadcast"] ?? false,
      isForwarded: json["isForwarded"] ?? false,
      hasReaction: json["hasReaction"] ?? false,
      ephemeralOutOfSync: json["ephemeralOutOfSync"] ?? false,
      productHeaderImageRejected: json["productHeaderImageRejected"] ?? false,
      lastPlaybackProgress: json["lastPlaybackProgress"] ?? 0,
      isDynamicReplyButtonsMsg: json["isDynamicReplyButtonsMsg"] ?? false,
      isMdHistoryMsg: json["isMdHistoryMsg"] ?? false,
      stickerSentTs: json["stickerSentTs"] ?? 0,
      requiresDirectConnection: json["requiresDirectConnection"] ?? false,
      pttForwardedFeaturesEnabled: json["pttForwardedFeaturesEnabled"] ?? false,
      caption: json["caption"] ?? "",
    );
  }

  Map<String, dynamic> toJson() => {
        "id": id?.toJson(),
        "body": body,
        "type": type,
        "t": t,
        "notifyName": notifyName,
        "from": from,
        "to": to,
        "self": self,
        "isNewMsg": isNewMsg,
        "star": star,
        "kicNotified": kicNotified,
        "recvFresh": recvFresh,
        "isFromTemplate": isFromTemplate,
        "pollInvalidated": pollInvalidated,
        "broadcast": broadcast,
        "isForwarded": isForwarded,
        "hasReaction": hasReaction,
        "ephemeralOutOfSync": ephemeralOutOfSync,
        "productHeaderImageRejected": productHeaderImageRejected,
        "lastPlaybackProgress": lastPlaybackProgress,
        "isDynamicReplyButtonsMsg": isDynamicReplyButtonsMsg,
        "isMdHistoryMsg": isMdHistoryMsg,
        "stickerSentTs": stickerSentTs,
        "requiresDirectConnection": requiresDirectConnection,
        "pttForwardedFeaturesEnabled": pttForwardedFeaturesEnabled,
        "caption": caption,
      };
}

Failed to initialize wpp

The application also gives an error. Example I tried the application but it gives an error can you check it?

[WhatsappBotFlutter] [ WhatsappException type : WhatsappExceptionType.failedToConnect , message : Failed to initialize WPP

[WhatsappBotFlutter] ConsoleLog: Error with Permissions-Policy header: Unrecognized feature: 'battery'.
[WhatsappBotFlutter] ConsoleLog: Error with Permissions-Policy header: Unrecognized feature: 'bluetooth'.
[WhatsappBotFlutter] ConsoleLog: Error with Permissions-Policy header: Unrecognized feature: 'hid'.
[WhatsappBotFlutter] ConsoleLog: Error with Permissions-Policy header: Origin trial controlled feature not enabled: 'interest-cohort'.
[WhatsappBotFlutter] ConsoleLog: Error with Permissions-Policy header: Unrecognized feature: 'local-fonts'.
[WhatsappBotFlutter] ConsoleLog: Error with Permissions-Policy header: Unrecognized feature: 'otp-credentials'.
[WhatsappBotFlutter] injected Wpp
[WhatsappBotFlutter] [ WhatsappException type : WhatsappExceptionType.failedToConnect , message : Failed to initialize WPP ]

Dependency conflict when using whatsapp_bot_flutter without Flutter

When trying to use the whatsapp_bot_flutter package in a pure Dart project (without Flutter), a dependency conflict arises due to the requirement of the sky_engine package. The following error occurs when running dart pub get:

Resolving dependencies...
Because no versions of whatsapp_bot_flutter match >0.1.1 <0.2.0 and whatsapp_bot_flutter 0.1.1 depends on flutter_inappwebview ^5.7.2+3, whatsapp_bot_flutter ^0.1.1 requires flutter_inappwebview ^5.7.2+3.
And because no versions of flutter_inappwebview match >5.7.2+3 <6.0.0, whatsapp_bot_flutter ^0.1.1 requires flutter_inappwebview 5.7.2+3.
And because flutter_inappwebview 5.7.2+3 depends on flutter from sdk which depends on sky_engine from sdk, whatsapp_bot_flutter ^0.1.1 requires sky_engine from sdk.
So, because sky_engine from sdk doesn't exist (could not find package sky_engine in the Flutter SDK) and wwdart depends on whatsapp_bot_flutter ^0.1.1, version solving failed.
exit code 69

Expected Behavior:

When using whatsapp_bot_flutter in a pure Dart project, it should not have a dependency on the sky_engine package, as this package is specific to Flutter and not available in the Dart SDK.

Steps to Reproduce:

Create a new pure Dart project.
Add whatsapp_bot_flutter as a dependency in the pubspec.yaml file.
Run dart pub get to fetch the dependencies.

Environment:

Dart SDK version: [insert your Dart SDK version]
Operating System: [insert your operating system]
Additional Information:
Please note that I am using a pure Dart project without Flutter, and the whatsapp_bot_flutter package is requesting the sky_engine package, which is not available in the Dart SDK.

Trying to help:

Maybe we need do something like this:
image

And abstract someway this lib: flutter_inappwebview

Mute / Unmute not working with the latest version

Successfully setup up the mobile option. I can pretty do everything successfully except muting and unmuting. I can see that the mute expiration get set properly, but the chat in the WhatsApp application is not muted. "canMute" returns true.

Vice-versa, I muted a chat in the WhatsApp app, but unmuting using the script doesn't work.

Any advice?

Errors of client.chat.sendTextMessage() method

There seems to be some parsing/escaping issues on the .sendTextMessage() method.

if I try to send "hello world" error is caused by quotes.

Unhandled exception:
Evaluation failed: SyntaxError: missing ) after argument list
#0      ExecutionContext._evaluateInternal (package:puppeteer/src/page/execution_context.dart:151:11)
<asynchronous suspension>
#1      ExecutionContext.evaluate (package:puppeteer/src/page/execution_context.dart:76:20)
<asynchronous suspension>
#2      WpClientDesktop.evaluateJs (package:whatsapp_bot_flutter/src/clients/wpclient_desktop.dart:24:22)
<asynchronous suspension>
#3      WppChat.sendTextMessage (package:whatsapp_bot_flutter/src/wpp/wpp_chat.dart:19:12)
<asynchronous suspension>

if I try to send hello world\nnext line error is caused by \n.

Unhandled exception:
Evaluation failed: SyntaxError: Invalid or unexpected token
#0      ExecutionContext._evaluateInternal (package:puppeteer/src/page/execution_context.dart:151:11)
<asynchronous suspension>
#1      ExecutionContext.evaluate (package:puppeteer/src/page/execution_context.dart:76:20)
<asynchronous suspension>
#2      WpClientDesktop.evaluateJs (package:whatsapp_bot_flutter/src/clients/wpclient_desktop.dart:24:22)
<asynchronous suspension>
#3      WppChat.sendTextMessage (package:whatsapp_bot_flutter/src/wpp/wpp_chat.dart:19:12)
<asynchronous suspension>

I am sure there will be more errors down the rabbit hole waiting to be discovered, I tried to debug but since I have no experience with puppeteer, can't do much, do you have any idea to resolve this issue?

[New feature] Send & remove emoji reaction

Working fine ✅

  /// Send emoji reaction to message
  /// Emoji list: https://unicode.org/emoji/charts/full-emoji-list.html
  /// To remove reaction, set [emoji] to null
  Future sendReactionToMessage({
    required MessageId messageId,
    String? emoji,
  }) async {
    final serialized = messageId.serialized;
    return wpClient.evaluateJs(
      '''WPP.chat.sendReactionToMessage(${serialized.jsParse}, ${emoji != null ? emoji.jsParse : false});''',
      methodName: 'sendReactionToMessage',
    );
  }

about receiving image, files, voice notes, etc

Is it possible to receive files, voice notes, and videos?

For images, files, and images: I get an encoded base64 string, but after I decode it, it gives me a 1kb file that is so pixelated, you barely recognize the image.

For voice notes: you get an empty string

is there a catch where I have to code something or this is web.whatsapp limitation?

Send PDF file - file will not display on iOS WhatsApp app

When I try to send a PDF file using chat.sendFileMessage and fileType: WhatsappFileType.document the received file on WhatsApp iPhone will show as "application.pdf" but if I click to open it will show a blank screen, and written in the middle: "application.pdf - Microsoft Word 97-2004 document"

Delete message

Hey,

I am trying to delete a message but I can't for some reasons.
It breaks my session and give the error message Evaluation failed: SyntaxError: Invalid or unexpected token

const groupId = "[email protected]";

       client.chat.deleteMessages(
       phone: groupId,
       messageIds: <String>["3EB046A9842E96D7F"],
    );

What is please the good way to do it?

Add SendButtonMessage Feature

Could you add SendButtonMessage feature on this? It could be complete whatsapp bot if there is SendButtonMessage.

On Windows: Login Failed

Hello,
I try to use this package in Flutter app on Windows but i get the following error after 2 login attemps:

█ ▀▀▀ █ ██▀ ▄ ▀▄ █ ▀ ▀▀ █ ▀▀█ ▄██▄ ▄▀ ██▄▄▀ ▀ ███▀▄▀
▀▀▀▀▀▀▀ ▀ ▀▀ ▀▀▀▀▀▀▀▀ ▀▀▀▀▀ ▀▀ ▀▀▀▀ ▀▀ ▀

[WhatsappBotFlutter] Checking QRCode status...
[WhatsappBotFlutter] Login Failed

How to login from mobile?

Hi. I'm unable to use the plugin on mobile because I can't login.

  • How do I login from the same mobile that's displaying QR Code?
  • What to do with QR Code after displaying?

My WhatsAppClient is null. What do I do? Here is my code so far:

void _sendMessage() async {
  setState(() => _processing = 'Initializing WhatsApp Chatbot');

  final client = await WhatsappBotFlutterMobile.connect(
    saveSession: true,
    onConnectionEvent: (event) => debugPrintSynchronously('Connection Event: ${event.name}'),
    onQrCode: (qrCodeUrl, qrCodeImage) {
      debugPrintSynchronously('Connection QR Code URL: $qrCodeUrl');
    },
  ).catchError((error) {
    debugPrintSynchronously('There was an error initializing the whatsapp client: $error');
    return null;
  });

  if (client == null) {
    ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
      backgroundColor: Clr.red,
      content: Text('WhatsApp Connection Failed. Client is null'),
    ));
    setState(() => _processing = null);
    return;
  }

  setState(() => _processing = 'Sending Message');
  if (_text.isNotEmpty) await client.chat.sendTextMessage(phone: '918892100457', message: _text);
}

Keep Authentication

Awesome lib, I started to port the whatsweb.js to dart but I found this lib. Nice work.
One question, we have any way to maintain the authentication yet? Like this:

image

Error Bad state: No element

my code:

WhatsappClient client = await WhatsappBotFlutter.connect(
      sessionDirectory: './chrome/cache',
      chromiumDownloadDirectory: './chrome/local-chromium',
      headless: false,
      onConnectionEvent: (ConnectionEvent event) {
        print(event.toString());
      },
      onQrCode: (String qr, Uint8List? imageBytes) {
        final qrText = WhatsappBotUtils.convertStringToQrCode(qr);
        print(qrText);
      },
      onBrowserCreated: (browser) {
        pid = browser.process?.pid ?? 0;
        print('pid=$pid');
        file.writeAsStringSync(pid.toString());
      },
    );

I got the error:
Exception has occurred.
StateError (Bad state: No element)

Google chrome is opened, but i got the error before that the whatsapp web shown

Status

How to get below status
Invalid whatsapp number,
Message sent
Message Failed

Whatsapp new code login

With the new update, whatsap web is also using the code for login, is there an update for it? Thank you 💐❤️

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.