<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Sajid Shaikh on Medium]]></title>
        <description><![CDATA[Stories by Sajid Shaikh on Medium]]></description>
        <link>https://medium.com/@sajid20shaikh?source=rss-2e27d0c4682e------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/0*NOw7mMaOs_AoXfvz</url>
            <title>Stories by Sajid Shaikh on Medium</title>
            <link>https://medium.com/@sajid20shaikh?source=rss-2e27d0c4682e------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 24 May 2026 02:24:44 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@sajid20shaikh/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Isar vs Hive: Why Isar Feels Faster in Real Flutter Apps]]></title>
            <link>https://medium.com/@sajid20shaikh/isar-vs-hive-why-isar-feels-faster-in-real-flutter-apps-2efd596ffd9d?source=rss-2e27d0c4682e------2</link>
            <guid isPermaLink="false">https://medium.com/p/2efd596ffd9d</guid>
            <category><![CDATA[offline]]></category>
            <category><![CDATA[hive]]></category>
            <category><![CDATA[isar]]></category>
            <category><![CDATA[flutter]]></category>
            <dc:creator><![CDATA[Sajid Shaikh]]></dc:creator>
            <pubDate>Wed, 03 Dec 2025 12:41:24 GMT</pubDate>
            <atom:updated>2025-12-03T12:41:24.859Z</atom:updated>
            <content:encoded><![CDATA[<p>When I started working with local storage in Flutter, my first choice — like many developers — was Hive. It has more than a million downloads, it’s easy to use, and it has been around for years.</p><p>But recently, I tried Isar for one of my projects, and the difference in performance was very clear. This article is my honest, humble experience of how <strong>Isar feels faster than Hive</strong>, especially when the app grows.</p><h3>Hive is Good… Until Data Grows</h3><p>Hive is perfect for simple things:</p><ul><li>Storing small objects</li><li>Saving a few settings</li><li>Keeping user preferences</li></ul><p>But when I started storing <strong>large lists</strong>, like:</p><ul><li>products</li><li>categories</li><li>cart items</li><li>offline caching</li></ul><p>Hive started slowing down.<br> Searching, sorting, and filtering needed manual loops in Dart, and the performance dropped when the data increased.</p><h3>Isar Feels Modern and Fast</h3><p>Isar is built differently.<br> It uses a native engine under the hood and supports:</p><ul><li>indexing</li><li>relations</li><li>fast filtering</li><li>instant queries</li></ul><p>When I moved the same product list to Isar, I noticed:</p><ul><li>Faster write</li><li>Faster read</li><li>Faster search</li><li>No lag in UI</li></ul><p>Even with hundreds or thousands of records, Isar stays smooth.</p><h3>The Surprising Part: Fewer Downloads, Better Performance</h3><p>Yes, Hive has <strong>1M+ downloads</strong>,<br> and Isar has around <strong>8K</strong>.</p><p>But that doesn’t mean Hive is better.</p><p>Hive has been around for many years.<br> Isar is new, and new things always start small.</p><p>But the performance speaks for itself.</p><h3>Where Isar Makes a Big Difference</h3><p>If your project needs:</p><ul><li>Offline mode</li><li>Fast product loading</li><li>Search and filters</li><li>Large lists</li><li>User data + relations</li></ul><p>Isar handles these cases much better.<br> Hive is simple, but it is not designed for heavy offline apps.</p><h3>When Hive Still Makes Sense</h3><p>I still use Hive for:</p><ul><li>Theme settings</li><li>Simple key-value storage</li><li>Very small data</li></ul><p>For everything else, I now prefer Isar.</p><h3>My Personal Verdict</h3><p>Both Hive and Isar are good.<br> But <strong>for modern Flutter apps</strong>, especially e-commerce or apps with offline features, <strong>Isar feels faster, cleaner, and more future-ready</strong>.</p><p>This is just my humble experience.<br> Your use case might be different, but if you haven’t tried Isar yet, it’s worth giving it a chance.</p><pre>isar 3.1.0+1</pre><p><a href="https://pub.dev/packages/isar/versions">https://pub.dev/packages/isar/versions</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=2efd596ffd9d" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to Add Full Huawei Device Support in Your Flutter App (2026 Guide)]]></title>
            <link>https://medium.com/@sajid20shaikh/how-to-add-full-huawei-device-support-in-your-flutter-app-2026-guide-206299fba2f8?source=rss-2e27d0c4682e------2</link>
            <guid isPermaLink="false">https://medium.com/p/206299fba2f8</guid>
            <category><![CDATA[android]]></category>
            <category><![CDATA[cross-platform]]></category>
            <category><![CDATA[huawei-mobile-service]]></category>
            <category><![CDATA[huawei]]></category>
            <category><![CDATA[flutter]]></category>
            <dc:creator><![CDATA[Sajid Shaikh]]></dc:creator>
            <pubDate>Wed, 03 Dec 2025 06:16:57 GMT</pubDate>
            <atom:updated>2025-12-03T06:16:57.401Z</atom:updated>
            <content:encoded><![CDATA[<p><strong>Handle GMS-less Devices, Replace Firebase, and Build HMS-Compatible Flavors</strong></p><p>Huawei devices without Google Mobile Services (GMS) behave differently from regular Android phones. Many Flutter apps break on Huawei phones because they rely on Firebase, Google Maps, YouTube APIs, or Google Sign-In.</p><p>In this article, I will walk you through everything you need to make your Flutter app compatible with Huawei HMS devices — including package replacements, flavor setup, YouTube alternatives, and real-world code snippets.</p><h3>Why You Must Add Huawei Support</h3><p>Since Huawei devices ship without GMS, the following Google services will not work:</p><p>Firebase Messaging</p><p>Google Maps</p><p>Google Places</p><p>Google Login</p><p>YouTube player APIs</p><p>Some WebViews that depend on GMS codecs</p><p>MLKit Text Recognition</p><p><strong>Step 1 — Detect Whether the Device Is Huawei (Without GMS)</strong></p><pre>import &#39;package:device_info_plus/device_info_plus.dart&#39;;<br>import &#39;dart:io&#39;;<br><br>Future&lt;bool&gt; isHuaweiDevice() async {<br>  final deviceInfo = DeviceInfoPlugin();<br><br>  if (Platform.isAndroid) {<br>    final androidInfo = await deviceInfo.androidInfo;<br>    return androidInfo.manufacturer.toLowerCase().contains(&#39;huawei&#39;) ||<br>           androidInfo.brand.toLowerCase().contains(&#39;huawei&#39;);<br>  }<br>  return false;<br>}<br>//Create utils fucntions<br><br>Usage:<br>final isHuawei = await isHuaweiDevice();</pre><h3>Step 2 — Replace Firebase Packages with Huawei HMS Alternatives</h3><p>Add these to pubspec.yaml:</p><pre>huawei_agconnect: ^1.8.0<br>huawei_analytics: ^6.12.0<br>agconnect_crash: ^1.9.0+300<br>huawei_push: ^6.13.0<br>huawei_remoteconfig: ^6.7.0</pre><p>Push Notifications Migration</p><pre>import &#39;package:huawei_push/huawei_push.dart&#39;;<br><br>void initHuaweiPush() async {<br>  Push.getTokenStream.listen((token) {<br>    print(&quot;Huawei Token: $token&quot;);<br>  });<br><br>  await Push.getToken(&quot;&quot;);<br>}</pre><h3>Step 3 — Replace Google-specific Packages</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*v2KAFqCoWQ-DaYFP0WbyEQ.png" /><figcaption>Add these alternative HMS plugins:</figcaption></figure><pre>huawei_account: ^6.12.0<br>huawei_map: ^6.5.0<br>huawei_site: ^6.7.0<br>huawei_mltext: ^3.12.0<br>huawei_player: ^6.7.0</pre><h3>Step 4 — YouTube Playback on Huawei Devices</h3><p>YouTube depends heavily on Google Play Services.<br> On Huawei devices, the YouTube Player plugin often fails.<br>Solution 1 — Use WebView with Huawei WebView</p><pre>huawei_webview: ^6.6.0</pre><p>Solution 2 — Use Huawei Player as Fallback</p><pre>if (await isHuaweiDevice()) {<br>  HuaweiPlayer.play(&#39;your_video_url&#39;);<br>} else {<br>  // Open YouTube embed<br>  final url = &quot;https://youtube.com/embed/$videoId&quot;;<br>  // use your normal player<br>}</pre><h3>Step 5 — Configure Android Flavors for Firebase &amp; Huawei</h3><p>The cleanest setup is using <strong>two app flavors</strong>:</p><ul><li><strong>huawei</strong> (HMS only)</li><li><strong>appMarket2 / google / global</strong> (normal GMS version)</li></ul><pre>android {<br>    flavorDimensions &quot;flavor&quot;<br><br>    productFlavors {<br>        huawei {<br>            applicationId &quot;com.myapp.huawei&quot;<br>            dimension &quot;flavor&quot;<br>        }<br>        appMarket2 {<br>            applicationId &quot;com.myapp.global&quot;<br>            dimension &quot;flavor&quot;<br>        }<br>    }<br>}</pre><h3>Add config files</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/854/1*o_Vb9_uq2uQyRP21MfrRyQ.png" /><figcaption>Build commands</figcaption></figure><pre>./gradlew assembleHuaweiDebug<br>./gradlew assembleAppMarket2Debug</pre><h3>Step 6— Final Recommendations</h3><h3>Test on Real HMS Device or Huawei Cloud Debugging</h3><p>Huawei provides cloud-based P40/P50/ Mate devices for testing.</p><h3>Do Not Break Your Existing GMS App</h3><p>Keep two flavor builds — safest architecture.</p><h3>Disable Google Login Button on Huawei Devices</h3><p>User experience stays clean, avoids crashes.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=206299fba2f8" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[GraphQL in Flutter best practice simple Demo]]></title>
            <link>https://medium.com/@sajid20shaikh/graphql-in-flutter-best-practice-using-repository-simple-demo-f5611e4b976e?source=rss-2e27d0c4682e------2</link>
            <guid isPermaLink="false">https://medium.com/p/f5611e4b976e</guid>
            <category><![CDATA[flutter]]></category>
            <category><![CDATA[graphql]]></category>
            <category><![CDATA[api]]></category>
            <category><![CDATA[app-development]]></category>
            <category><![CDATA[android]]></category>
            <dc:creator><![CDATA[Sajid Shaikh]]></dc:creator>
            <pubDate>Mon, 01 Jul 2024 15:26:10 GMT</pubDate>
            <atom:updated>2024-07-01T16:39:47.451Z</atom:updated>
            <content:encoded><![CDATA[<p>Integrated graphQL api in flutter with best Practice</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/860/1*rZgH3xu4OoNt7hPZ4DNxmA.png" /></figure><p>GraphQL is a query language for APIs that provides a more efficient, powerful, and flexible alternative to REST. When using GraphQL in a Flutter application, you can query exactly the data you need and nothing more. This helps reduce the amount of data transferred over the network, leading to better performance and user experience. Here are the steps to integrate GraphQL in a Flutter app:</p><blockquote><strong>Yes, GraphQL offers three primary operations that greatly simplify how we interact with data: queries, mutations, and subscriptions. Each serves a different purpose and provides flexibility in managing data interactions within your application.</strong></blockquote><h3>Queries</h3><p>Queries are used to fetch data from the server. They allow you to specify exactly what data you need, reducing the amount of data transferred and improving efficiency. Here’s an example of a simple query to fetch user details:</p><h3>Mutations</h3><p>Mutations are used to modify data on the server (create, update, delete). They work similarly to queries but are designed to change data and often require input parameters. Here’s an example mutation to update a user’s email:</p><h3>Subscriptions</h3><p>Subscriptions allow you to listen for real-time updates from the server. They are useful for applications that need to react to data changes instantly, such as chat applications or live updates. Here’s an example of a subscription to listen for new user creations:</p><h3>Step 1: Add Dependencies</h3><pre>graphql_flutter: ^5.0.0<br>graphql: ^5.1.3 # To call graphql api, platform: All.<br>graphql_codegen: ^0.14.0 # To generate graphql related classes, platform: All.<br>hive: ^2.2.3<br>dio:<br>graphql_flutter: ^5.1.2<br>build_runner:</pre><h3>Step 2: Create build.yaml file</h3><pre># build.yaml<br><br>targets:<br>  $default:<br>    builders:<br>      graphql_codegen:<br>        options:<br>          clients:<br>            - graphql<br>          outputDirectory: graphql_gen<br>          addTypename: false<br>          generatedFileHeader: &quot;/// GENERATED CODE - DO NOT MODIFY BY HAND\n<br>/// *****************************************************\n<br>///  FlutterGen\n<br>/// *****************************************************\n\n<br>// coverage:ignore-file\n<br>// ignore_for_file: type=lint\n<br>// ignore_for_file: directives_ordering,unnecessary_import,implicit_dynamic_list_literal,deprecated_member_use\n\n&quot;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/297/1*b4UPOheZUFRfTZG27q3Ydg.png" /></figure><h3>Step 3: Add graphQL Schema in lib folder</h3><p>After schema add in your project</p><p>flutter pub run build_runner build</p><pre>flutter pub run build_runner build</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/280/1*BtVx-JakmLZ6fEboZ-w_Hw.png" /><figcaption>After build the code gen file is shown in your project like this</figcaption></figure><p>Here all your project is successfully setup graphql</p><h3>Now move Graphql client</h3><h3>Step 4: Create GraphQLConfig client class</h3><pre>class GraphQLConfig {<br>  final connectivity = Connectivity();<br>  static HttpLink httpLink = HttpLink(&#39;Add your graphql server url&#39;);<br><br>  GraphQLClient clientToQuery() =&gt; GraphQLClient(<br>      link: httpLink,<br>      cache: GraphQLCache(store: InMemoryStore()),<br>      defaultPolicies: DefaultPolicies(<br>        mutate: Policies(<br>          cacheReread: CacheRereadPolicy.ignoreAll,<br>          error: ErrorPolicy.all,<br>          fetch: FetchPolicy.noCache,<br>        ),<br>        query: Policies(<br>          cacheReread: CacheRereadPolicy.ignoreAll,<br>          error: ErrorPolicy.all,<br>          fetch: FetchPolicy.noCache,<br>        ),<br>      ));<br>}</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/783/1*y2iMeVBv0O4qzHzH0621Vw.png" /></figure><h3>Step 5: Create GraphQLService class</h3><pre>class GraphQLService {<br>  static GraphQLConfig graphQLConfig = GraphQLConfig();<br>  GraphQLClient client = graphQLConfig.clientToQuery();<br>}</pre><h3>Step 6: Wrap Material app into GraphQLProvider</h3><pre>class MyApp extends StatelessWidget {<br>  const MyApp({super.key});<br><br>  @override<br>  Widget build(BuildContext context) {<br>    return GraphQLProvider(<br>      client: ValueNotifier(GraphQLService().client),<br>      child: MaterialApp(<br>        title: &#39;Flutter Demo&#39;,<br>        debugShowCheckedModeBanner: false,<br>        theme: ThemeData(<br>          colorScheme: ColorScheme.fromSwatch(primarySwatch: Colors.deepPurple),<br>          // Consider removing useMaterial3: true if you&#39;re not targeting Flutter 3.0 or later<br>          useMaterial3: true,<br>        ),<br>        home: const OtpPage(), // Set the OTP page as the home page<br>      ),<br>    );<br>  }<br>}</pre><h3>GraphQLProvider</h3><h3>Step 7: Add your Mutation or query as per you requirement</h3><pre><br>mutation SendOtp($input:SendOTPInput!) {<br>    sendOTP(input: $input) {<br>        meta {<br>            status<br>            message<br>            message_code<br>            status_code<br>        }<br>    }<br>}</pre><pre>send_otp.graphql<br><br>file name</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/948/1*rpbXUwvfaGf_tueR7q0sUA.png" /><figcaption>After add mutation run this cammand flutter pub run build_runner build</figcaption></figure><h3>Step 8 : Create Repository</h3><pre>import &#39;package:graphql_flutter/graphql_flutter.dart&#39;;<br>import &#39;../graphql/graphql_gen/send_otp.graphql.dart&#39;;<br><br>class OtpRepository {<br>  final GraphQLClient _client;<br><br>  OtpRepository(this._client);<br><br>  Future&lt;Mutation$SendOtp$sendOTP$meta?&gt; sendOTP({<br>    required String version,<br>    required String platform,<br>    required String phoneCountryId,<br>    required String mobileNumber,<br>  }) async {<br>    const String mutation = r&#39;&#39;&#39;<br>      mutation SendOtp($input: SendOTPInput!) {<br>        sendOTP(input: $input) {<br>          meta {<br>            status<br>            message<br>            message_code<br>            status_code<br>          }<br>        }<br>      }<br>    &#39;&#39;&#39;;<br><br>    final options = MutationOptions(<br>      document: gql(mutation),<br>      variables: {<br>        &#39;input&#39;: {<br>          &#39;version&#39;: version,<br>          &#39;platform&#39;: platform,<br>          &#39;phone_country_id&#39;: phoneCountryId,<br>          &#39;mobile_number&#39;: mobileNumber,<br>        },<br>      },<br>    );<br><br>    final result = await _client.mutate(options);<br><br>    print(&#39;sajid : ${result.data}&#39;);<br><br>    if (result.hasException) {<br>      print(&#39;GraphQL Exception: ${result.exception.toString()}&#39;);<br>      throw Exception(&#39;Failed to send OTP&#39;); // Throw an error to handle in UI<br>    }<br><br>    final meta = result.data?[&#39;sendOTP&#39;][&#39;meta&#39;];<br>    return meta != null<br>        ? Mutation$SendOtp$sendOTP$meta.fromJson(meta)<br>        : null; // Return parsed meta data or null if not present<br>  }<br>}</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/276/1*IsUo-FnetkIztBskJt-VaA.png" /></figure><h3>Step 8 : Create this function calling in controller or cubit if you are using state management but in this demo normal UI</h3><pre>void _sendOTP() async {<br>    final otpRepository = OtpRepository(GraphQLService().client);<br>    try {<br>      final result = await otpRepository.sendOTP(<br>        version: &#39;1.0&#39;,<br>        platform: &#39;Android&#39;,<br>        phoneCountryId: &#39;1&#39;,<br>        mobileNumber: phoneNumber,<br>      );<br><br>      if (kDebugMode) {<br>        print(&quot;result sajid  ${result?.message}&quot;);<br>        print(&quot;result sajid  ${result?.message_code}&quot;);<br>        print(&quot;result sajid  ${result?.status_code}&quot;);<br>      }<br><br>      if (result != null) {<br>        if (result.status_code == 200) {<br>          Navigator.push(<br>            context,<br>            MaterialPageRoute(builder: (context) =&gt;  VerifyOtpPage()),<br>          );<br>        }<br>        ScaffoldMessenger.of(context).showSnackBar(<br>          const SnackBar(content: Text(&#39;OTP sent successfully&#39;)),<br>        );<br>      } else {<br>        ScaffoldMessenger.of(context).showSnackBar(<br>          const SnackBar(content: Text(&#39;Failed to send OTP&#39;)),<br>        );<br>      }<br>    } catch (e) {<br>      print(&#39;Error sending OTP: $e&#39;);<br>      ScaffoldMessenger.of(context).showSnackBar(<br>        const SnackBar(content: Text(&#39;Failed to send OTP&#39;)),<br>      );<br>    }<br>  }</pre><h3>Step 9: Call into our widget</h3><pre>class MyCustomForm extends StatefulWidget {<br>  const MyCustomForm({super.key});<br><br>  @override<br>  MyCustomFormState createState() =&gt; MyCustomFormState();<br>}<br><br>class MyCustomFormState extends State&lt;MyCustomForm&gt; {<br>  final _formKey = GlobalKey&lt;FormState&gt;();<br>  final String phoneNumber = &quot;7415311601&quot;;<br><br>  @override<br>  void initState() {<br>    super.initState();<br>  }<br><br>  @override<br>  Widget build(BuildContext context) {<br>    return Form(<br>      key: _formKey,<br>      child: Column(<br>        crossAxisAlignment: CrossAxisAlignment.start,<br>        children: [<br>          TextFormField(<br>            initialValue: phoneNumber,<br>            keyboardType: TextInputType.number,<br>            inputFormatters: [FilteringTextInputFormatter.digitsOnly],<br>            decoration: const InputDecoration(<br>              labelText: &#39;Enter Phone Number&#39;,<br>              border: OutlineInputBorder(),<br>            ),<br>            validator: (value) {<br>              if (value == null || value.isEmpty) {<br>                return &#39;Please enter some text&#39;;<br>              }<br>              return null;<br>            },<br>            onChanged: (value) {<br>              //phoneNumber = value.toString();<br>            },<br>          ),<br>          Padding(<br>            padding: const EdgeInsets.symmetric(vertical: 16),<br>            child: ElevatedButton(<br>              onPressed: () {<br>                if (_formKey.currentState!.validate()) {<br>                  // Call sendOTP mutation here<br>                  _sendOTP();<br>                }<br>              },<br>              child: const Text(&#39;Submit&#39;),<br>            ),<br>          ),<br>        ],<br>      ),<br>    );<br>  }</pre><p><a href="https://github.com/sajidshaikh20/Flutter_graphQL_demo">GitHub - sajidshaikh20/Flutter_graphQL_demo</a></p><p>Switch master branch</p><p>Thank you for taking the time to read through this tutorial on [Graoh ql in flutter I hope you found it helpful and that it gave you a better understanding of [ Graphql concept ]. If you have any questions or need further clarification, feel free to leave a comment below or reach out to me directly.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f5611e4b976e" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>